C++11:列表初始化、声明、STL升级
1、列表初始化
1.1 C++98传统的{}
在C++98中,标准允许使用花括号{}对数组或结构体元素进行统一的列表初始化
cpp
struct Point
{
int _x;
int _y;
};
int main()
{
int array1[] = { 1, 2, 3, 4, 5 };
int array2[5] = { 0 };
Point p = { 1, 2 };
return 0;
}
1.2 C++11中的{}
C++扩大了用大括号括起的列表(初始化列表)的使用范围,试图实现⼀切对象皆可用{}初始化,{}初始化的过程中,可以省略掉=,但建议不去掉=
cpp
int main()
{
int array1[] = { 1, 2, 3, 4, 5 };
int array2[5] = { 0 };
Point p = { 1, 2 };
// C++11中列表初始化应用在内置类型上
int x1 = 1;
int x2 = { 1 };
int x3{ 1 };
return 0;
}
创建对象时也可以使用列表初始化的方式来调用构造函数初始化
cpp
class Date
{
public:
Date(int year = 1, int month = 1, int day = 1)
:_year(year)
, _month(month)
, _day(day)
{
cout << "Date(int year, int month, int day)" << endl;
}
Date(const Date& d)
:_year(d._year)
, _month(d._month)
, _day(d._day)
{
cout << "Date(const Date& d)" << endl;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1(2025, 9, 18);
Date d2 = { 2025, 9, 18 };
Date d3{ 2025, 9, 18 }; // 可以省略赋值符号
const Date& d4 = { 2024, 7, 25 };
// 需要注意的是C++98支持单参数时类型转换,也可以不用{}
Date d5 = { 2025 };
Date d6 = 2025;
return 0;
}
2、C++11中的std::initializer_list
模拟实现vector中的{}初始化演示效果
cpp
template<class T>
class vector {
public:
typedef T* iterator;
vector(initializer_list<T> l)
{
for (auto e : l)
push_back(e)
}
// 赋值
vector& operator= (initializer_list<T> il)
{
vector<T> tmp(il);
swap(tmp);
return *this;
}
map& operator= (initializer_list<value_type> il);
private:
iterator _start = nullptr;
iterator _finish = nullptr;
iterator _endofstorage = nullptr;
};
std::initializer_list应用演示
cpp
int main()
{
vector<int> v1 = { 1,2,3,4,5,6,7,8,8}; // 任意多个int值的{}列表
v1 = { 1,2,3 };
auto il = { 1,2,3,4,5,6,7,8,8 };
cout << sizeof(il) << endl;
cout << typeid(il).name() << endl;
// 这里是pair对象的{}初始化和map的initializer_list构造结合到一起用了
map<string, string> dict = { {"sort", "排序"}, {"string", "字符串"} };
}
3、声明
C++11提供了多种简化声明的方式,尤其是在使用模板时
3.1 auto
在C++98中auto是存储类型的说明符,表明变量是局部自动存储类型,但是局部域中定义局部变量默认就是自动存储类型,所以auto就没什么价值了。C++11中废弃auto原来的用法,讲其用于实现自动类型判断。这样要求必须进行显示初始化,让编译器将定义对象的类型设置为初始化值的类型
cpp
int main()
{
int i = 10;
auto p = &i;
auto pf = strcpy;
cout << typeid(p).name() << endl;
cout << typeid(pf).name() << endl;
map<string, string> dict = { {"sort", "排序"}, {"insert", "插入"} };
//map<string, string>::iterator it = dict.begin();
auto it = dict.begin();
return 0;
}
输出结果:
int *
char * (__cdecl*)(char *,char const *)
3.2 不能使用auto的场景
- auto不能作函数形参
cpp
void func(auto x) {}
- auto不能作为函数的返回值
cpp
// C++11 报错,不能直接 auto 作返回值
auto test() {
return 10;
}
- 数组类型推导不能直接 auto 数组
cpp
int arr[5] = {1,2,3};
auto a = arr; // a 是 int*,不是数组,丢失数组长度信息
// 无法用 auto 保留原生数组类型,必须用 auto&
auto& a2 = arr; // 才是 int(&)[5]
- new 分配时不能用 auto 单独写
cpp
auto p = new auto(10);
4、STL中的变化
下图1圈起来的就是STL中的新容器,但是实际最有用的是unordered_map和unordered_set。这两个我们前面已经进行了非常详细的讲解,其他的大家了解⼀下即可。

STL中容器的新接口也不少,最重要的就是右值引⽤和移动语义相关的push/insert/emplace系列
接口和移动构造和移动赋值,还有initializer_list版本的构造等,这些前面都讲过了,还有一些无关痛痒的如cbegin/cend等需要时查查文档即可。