C++11概览与统一初始化

C++11是个分水岭。在这之前,C++标准委员会花了8年时间打磨,最终在2011年8月发布。它最初被叫做C++0x,因为原计划在2010年前推出,结果一拖再拖。C++11之后的节奏就稳了------每3年一个版本,C++14、17、20,规律迭代。

标准更新的动力很朴素:标准化既有实践,并提升抽象能力。比如列表初始化,就是想用一套语法覆盖所有初始化场景,省得你费心记各种形式的区别。

目录

[1. 从C++98的{}到C++11的统一初始化](#1. 从C++98的{}到C++11的统一初始化)

[2. std::initializer_list:让花括号更强大](#2. std::initializer_list:让花括号更强大)


1. 从C++98的{}到C++11的统一初始化

C++98里,花括号只能初始化数组和POD结构体:

cpp

复制代码
int arr[] = {1, 2, 3, 4, 5};
int arr2[5] = {0};
struct Point { int _x; int _y; };
Point p = {1, 2};

到了C++11,情况变了。一切对象都可以用{}初始化,内置类型、自定义类型、容器,一视同仁。甚至可以把等号省掉:

cpp

复制代码
int x1 = {2};
int x2{2};
Point p1{1, 2};
const Point& p2 = {1, 2};  // 引用绑定临时对象

class Date {
public:
    Date(int year = 1, int month = 1, int day = 1)
        : _year(year), _month(month), _day(day) { }
private:
    int _year, _month, _day;
};

Date d1 = {2025, 1, 1};    // 等价于 Date d1{2025, 1, 1}
const Date& d2 = {2024, 7, 25};  // 临时对象生命周期延长

这种写法背后发生了类型转换:{2025,1,1}会构造一个Date临时对象,再去拷贝给目标。但现代编译器会直接优化成原地构造,拷贝构造被消掉了。你可以自己加打印验证------拷贝构造不会被调用。

使用容器时,这种写法的便利性更明显:

cpp

复制代码
vector<Date> v;
v.push_back({2025, 1, 1});   // 比push_back(Date(2025,1,1))利落

2. std::initializer_list:让花括号更强大

上面的写法已经挺方便了,但还有一个需求没解决:用一堆值直接初始化容器。

cpp

复制代码
vector<int> v1 = {1, 2, 3, 4, 5};
vector<int> v2 = {1, 2, 3, 4, 5, 6, 7};

要支持这种用法,以前得写多个不同参数个数的构造函数。C++11通过std::initializer_list一劳永逸地解决了这个问题。

initializer_list内部可以理解为在栈上分配了一个临时数组,存两个指针(开始和结束),支持迭代器遍历。当你写下{1,2,3}时,编译器会为你构造一个initializer_list<int>对象。

cpp

复制代码
auto il = {10, 20, 30};  // il 类型为 initializer_list<int>
cout << sizeof(il) << endl;  // 典型实现为两个指针大小

STL容器都新增了接受initializer_list的构造函数和赋值运算符:

cpp

复制代码
vector(initializer_list<value_type> il,
       const allocator_type& alloc = allocator_type());
vector& operator=(initializer_list<value_type> il);
// list, map 同理

这样,任意多个值的初始化只需要一份实现:

cpp

复制代码
template<class T>
class my_vector {
public:
    my_vector(initializer_list<T> l) {
        for (auto e : l)
            push_back(e);
    }
    // ...
};

于是可以这样写:

cpp

复制代码
vector<int> v1({1,2,3,4,5});
vector<int> v2 = {1,2,3,4,5};
const vector<int>& v3 = {1,2,3,4,5};

map<string, string> dict = {{"sort", "排序"}, {"string", "字符串"}};

v1 = {10,20,30,40,50};   // initializer_list版本的赋值

值得注意的是,v1({1,2,3,4,5})是直接构造,v2 = {1,2,3,4,5}则是构造临时对象再通过拷贝/移动初始化v2,但编译器通常会优化成直接构造。两者语义上有细微差别,但实际运行效果往往一致。

列表初始化背后,本质是C++11对"统一抽象"的执念。一套语法,覆盖所有初始化场景,降低心智负担,这方向没错。

相关推荐
用户8055336980321 小时前
不止三件套:QObject 属性系统全关键字与运行时反射!
c++·qt
BadBadBad__AK1 天前
线段树维护区间 k 次方和
c++·数学·算法·stl
卷无止境2 天前
Eigen 库如何借助 OpenMP 加速计算
c++·后端
卷无止境2 天前
OpenMPI、MPICH 与 OpenMP:关系、核心概念与架构全解
c++·后端
郝学胜_神的一滴3 天前
CMake 30:循环语法全解|foreach_while双循环精讲、迭代技巧与实战避坑指南
c++·cmake
卷无止境5 天前
C++ 的Eigen 库全解析
c++
卷无止境5 天前
现代 C++特性大盘点:一门脱胎换骨的老语言
c++·后端
郝学胜_神的一滴5 天前
CMake 27:缓存变量的特性、语法、类型与实操全解
c++·cmake
博客18007 天前
酷宝的使用方法,超好用的免费界面库,C++、MFC可用
c++·mfc·界面库·库来帮·酷宝
郝学胜_神的一滴7 天前
CMake 026:属性体系精讲、四大作用域全解 & 实战代码落地
c++·cmake