北京市网站建设_网站建设公司_Ruby_seo优化
2025/12/18 18:47:00 网站建设 项目流程


关注我,学习c++不迷路:

个人主页:爱装代码的小瓶子
专栏如下:

  1. c++学习
  2. Linux学习

后续会更新更多有趣的小知识,关注我带你遨游知识世界

期待你的关注。


文章目录

  • 1. c++11的介绍:
  • 2. ``{}``初始化:
    • 2-1: 避免歧义和窄化转换问题:
    • 2-2 统一的样式进行初始化:
    • 2-3 对比两种初始化:
    • 2-4 陷阱:
  • 3. 为什么要做到统一初始化?
    • 1. **降低学习成本**
    • 2. **提高代码可读性和一致性**
    • 3. **与现代C++理念一致**
    • 总结

1. c++11的介绍:

C++11是C++历史上一次里程碑式的更新,它为这门古老而强大的语言注入了新的活力。在C++11之前,我们习惯了繁琐的构造函数调用、复杂的初始化语法,以及在传递临时对象时的性能损耗。但C++11的到来,彻底改变了这一切。

想象一下,你可以用统一的{}语法初始化任何类型——从内置类型到自定义类,从数组到容器,代码变得更加简洁优雅。更令人兴奋的是,C++11引入了右值引用和移动语义,让编译器能够"偷走"临时对象的资源,避免不必要的拷贝,从而大幅提升程序性能。

本文将带你深入探索C++11的这两个核心特性:首先是列表初始化(统一初始化),它让C++的初始化语法"大一统";然后是右值引用与移动语义,这是C++11性能优化的利器。无论你是C++新手还是资深开发者,这些特性都将让你的代码更现代、更高效。


2.{}初始化:

在c++11没有出来之前,我们初始化无法做到统一,而前复杂,还很麻烦:

我们还发现,我们还可以这样初始化:

最后一个a3这个变量明显是错误的,这又他的精度会明显变小,于此同时在初始化STL容器的时候很麻烦,我们需要一个一个的进行插入。或者在自定义变量中,初始化也是很麻烦的事情。总之初始化变量,这个事情可谓是八仙过海各显神通。

// C++11之前,容器初始化很繁琐std::vector<int>v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);std::vector<int>v2(5,1);// 5个元素,都是1std::vector<int>v3(5);// 5个默认初始化的元素// 对于map,更麻烦std::map<int,std::string>m;m[1]="one";m[2]="two";

在引入c++11后:

2-1: 避免歧义和窄化转换问题:

原来的精度问题得到有效解决:

原本的警告直接变成error,这一点在编译器中我们也可以看到,{}初始化会禁止窄化转换,让代码更安全。

2-2 统一的样式进行初始化:

无论你是STL的vector还是map或者set,还是自定义类型Data或者student,我们都可以尝试使用{}来进行初始化:

intx={1};doubley={1.2};vector<int>v({1,2,3,4,5,6});vector<int>v2={1,2,3,4,5,6};map<string,int>mp={{"1111",1},{"2222",2}};

这样看起来很是美观,这里是怎么做到的呢?这里其实引入了initializer_list。这是一个轻量级的容器:

// initializer_list是C++11引入的轻量级代理对象namespacestd{template<typenameT>classinitializer_list{private:constT*array;// 指向数组的指针size_t len;// 元素个数public:// 构造函数等};}

我们拿vector中拿来作比较:我们在{}里面的数字先构成了initializer_list,随后调用vector的构造函数完成来构造:

template<typenameT>classvector{public:// 1. 默认构造vector();// 2. 指定大小和值vector(size_t n,constT&value);// 3. 迭代器范围template<typenameInputIt>vector(InputIt first,InputIt last);// 4. initializer_list构造(C++11新增)vector(std::initializer_list<T>init);// 5. 拷贝/移动构造vector(constvector&other);vector(vector&&other);};

在这里我们可以看到很多构造函数。c++中总是调用自己最合适的函数:我们{}里面的变量已经构成了initializer_list,我们便可以调用4号来进行完成构造。

总结:
编译器背后做了什么:

  • 创建临时数组:在栈上创建int[5] = {1, 2, 3, 4, 5}
  • 创建initializer_liststd::initializer_list<int> il(&临时数组[0], 5)。
  • 调用匹配的构造函数:vector(il)拷贝或移动这些元素到vector内部。

再来说说,map是怎么初始化的:

template<typenameKey,typenameValue>classmap{public:// 接受pair的initializer_listmap(std::initializer_list<std::pair<constKey,Value>>init);};
std::map<int,std::string>m{{1,"one"},{2,"two"}};
  1. 外层{}:识别为initializer_list的参数
  2. 内层{1, “one”}:解析为std::pair<int, std::string>的初始化
  3. pair的构造:std::pair<const int, std::string>(1, “one”)
  4. 最终调用:map({pair1, pair2})

2-3 对比两种初始化:

我们来尝试多组对比:

vector<int>v(8,2);vector<int>v1{1,2,3,4,5,6,7,8};vector<int>v2={1,2,3,4,5,6,7,8};vector<int>v3({1,2,3,4,5,6,7,8});

这几个初始化有什么区别呢:

  1. 第一个是传统的c++初始化,全部初始化成:2。只有在特定的情况下使用。
  2. 第二个则是c++11初始化的标准,我们会调用vector(std::initializer_list<int> init)创建 8个元素,值分别为1到8。最推荐的现代C++写法。
  3. 第三个很像是拷贝列表初始化,在现代编译器中几乎和第二个相同,更像是赋值拷贝初始化。适用场景:v2更像"赋值"语义,v1更像"构造"语义。
  4. 第四个过于冗余了,显式创建一个initializer_list<int>临时对象调用构造函数:vector(std::initializer_list<int> init)多此一举,但语法合法。
初始化方式调用构造函数创建元素数量元素值推荐度
v(8, 2)vector(size_t, const T&)8个全是2⭐⭐⭐(特定场景)
v1{1,2,3,4,5,6,7,8}vector(initializer_list<T>)8个1-8⭐⭐⭐⭐⭐
v2 = {1,2,3,4,5,6,7,8}vector(initializer_list<T>)8个1-8⭐⭐⭐⭐
v3({1,2,3,4,5,6,7,8})vector(initializer_list<T>)8个1-8⭐⭐

2-4 陷阱:

classWidget{public:Widget(inta,intb){}Widget(std::initializer_list<int>list){}};Widgetw1(1,2);// 调用第一个构造函数Widget w2{1,2};// 调用第二个构造函数(initializer_list)Widgetw3(1,2,3);// 错误!Widget w4{1,2,3};// 调用第二个构造函数

在这段函数中,总是调用最合适自己的,那么第一个就会调用第一个构造函数,第二个由于大括号会调用第二个构造函数。第三个由于无法匹配导致错误。

classMyClass{inta;std::string b;public:// 1. initializer_list构造(不常用)MyClass(std::initializer_list<int>list){// 不推荐:类型不匹配}// 2. 多参数构造(推荐)MyClass(inta,std::string b):a(a),b(b){}// 3. 聚合类型(最简单)// 去掉构造函数,让struct成为聚合类型};// 使用MyClass obj{1,"hello"};// 调用构造函数 #2

3. 为什么要做到统一初始化?

1.降低学习成本

  • 旧的C++:需要掌握多种初始化方式

    • int x = 0;(赋值)
    • int x(0);(直接初始化)
    • int arr[] = {1,2,3};(聚合初始化)
    • std::vector<int> v(10, 1);(括号初始化)
  • 新的C++:一种方式搞定所有

    • int x{0};
    • int arr[]{1,2,3};
    • std::vector<int> v{10, 1};

2.提高代码可读性和一致性

// 以前,不同容器、不同类型的初始化语法不一致inta=1;intb(2);intc[]={3,4};std::vector<int>v(5,1);// 括号std::map<int,int>m{{1,2},{3,4}};// 双括号// 现在,统一用{},一眼就能看懂inta{1};intb{2};intc[]{3,4};std::vector<int>v{5,1};// 注意:这里含义不同了!std::map<int,int>m{{1,2},{3,4}};

3.与现代C++理念一致

C++11开始,C++致力于:

  • 更安全(类型安全、转换安全)
  • 更简洁(语法统一)
  • 更现代(符合现代编程语言趋势)
    C++98/03的初始化语法是"拼凑"出来的,不同场景用不同语法。统一初始化让C++从"方言"走向"标准语"。
    统一初始化为后续C++11/14/17/20的很多新特性提供了基础,比如:
  • 结构化绑定
  • 模板参数推导
  • 聚合初始化扩展

总结

统一初始化({})的核心价值

  1. 安全:防止意外的类型转换
  2. 统一:一种语法,多种场景
  3. 简洁:减少记忆负担
  4. 现代:让C++更符合现代语言标准

正如C++之父Bjarne Stroustrup所说:“我希望C++能有一种统一的初始化方式,让初始化不再令人困惑。”{}就是这个愿景的实现。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询