【C++ 学习 ㉘】- 详解 C++11 的列表初始化

news2025/7/19 21:02:59

目录

一、C++11 简介

二、列表初始化

2.1 - 统一初始化

2.2 - 列表初始化的使用细节

2.2.1 - 聚合类型的定义

2.2.2 - 注意事项

2.3 - initializer_list

2.3.1 - 基本使用

2.3.2 - 源码剖析


 


一、C++11 简介

  1. 1998 年,C++ 标准委员会发布了第一版 C++ 标准,即 C++98 标准,并计划以后每 5 年视实际需要更新一次标准。

    所谓标准,即明确 C++ 代码的编写规范,所有的 C++ 程序员都应遵守此标准

  2. 2003 年,C++ 标准委员会发布了第二版 C++ 标准,即 C++03 标准,但由于 C++03 仅修复了一些 C++98 中存在的漏洞,并未修改核心语法,因此人们习惯将这两个标准合称为 C++98/03 标准。

  3. 2011 年,C++ 标准委员会发布了第三版 C++ 标准,即 C++11 标准,相比 C++03,C++11 带来了数量可观的变化,其中包含了约 140 个新特性,以及对 C++03 中约 600 个缺陷的修正,这使得 C++11 更像从 C++98/03 中孕育出来的一种新语言。。

    C++ 标准委员会一开始是计划在 2007 年发布第三版 C++ 标准,即 C++07 标准,但在 2006 年时,标准委员会认为到 2007 年,甚至到 2008 年,都可能无法发布第三版 C++ 标准,所以干脆将第三版 C++ 标准命名为 C++0x,即计划在二十一世纪的第一个 10 年的某个时间发布,但最终直到 2011 年才发布第三版 C++ 标准


二、列表初始化

在 C++98/03 中,对象的初始化方式有很多种,这些不同的初始化方式都有各自的适用范围和作用,没有一种方式可以通用于所有情况。为了统一初始化方式,并且让初始化行为具有确定的效果,C++11 提出了列表初始化的概念

2.1 - 统一初始化

在 C++98/03 中,对于普通数组和可以直接进行内存拷贝(memcpy)的对象,可以使用列表初始化来初始化数据。

int arr[5] = { 0, 1, 2, 3, 4 };
​
struct Point
{
    int _x;
    int _y;
} p = { 0, 0 };

在 C++11 中,初始化列表的适用性被大大地增加了,它现在可以适用于任何类型对象的初始化

注意:在 C++11 中,使用列表初始化时,可以添加等号(=),也可以不添加等号

class A
{
public:
    A(int i = 0) : _i(i) { }
private:
    A(const A& a) : _i(a._i) { }
private:
    int _i;
};
​
int main()
{
    A a1(10);
    A a2 = 10;
    A a3 = { 10 };
    A a4{ 10 };
    return 0;
}
  1. a3、a4 使用了 C++11 的列表初始化来初始化对象,效果如同 a1 的直接初始化

  2. 至于 a2,10 会通过隐式类型转换调用构造函数 A(int i = 0) 构造出一个匿名对象,然后通过这个匿名对象调用拷贝构造函数 A(const A& a) 构造出 a2,但由于拷贝构造函数是私有的(private),所以编译器会报错

    注意:Linux 中的 g++ 编译器会报错,VS 中的编译器则不会报错

使用 new 操作符创建新对象时也可以使用列表初始化来初始化对象

int* p = new int{ 0 };
int* arr = new int[5]{ 0, 1, 2, 3, 4 };

除了上面所述的内容,列表初始化还可以直接用在函数传参和返回值上

#include <iostream>
#include <string>
using namespace std;
​
class Person
{
public:
    Person(int id, string name) : _id(id), _name(name)
    {
        cout << _id << ":" << _name << endl;
    }
private:
    int _id;
    string _name;
};
​
void func1(Person p) { }
​
Person func2() { return { 2, "李四" }; }
​
int main()
{
    func1({ 1, "张三" });  // 1:张三
    Person p = func2();  // 2:李四
    return 0;
}

 

2.2 - 列表初始化的使用细节

在 C++11 中,列表初始化的使用范围被大大地增加了,但一些模糊的概念也随之而来。

#include <iostream>
using namespace std;
​
struct T1
{
    int _x;
    int _y;
} t1{ 520, 520 };
​
struct T2
{
    int _x;
    int _y;
​
    T2(int, int) : _x(1314), _y(1314) { }
} t2{ 520, 520 };
​
int main()
{
    cout << t1._x << ", " << t1._y << endl;  // 520, 520
    cout << t2._x << ", " << t2._y << endl;  // 1314, 1314
    return 0;
}

在上面的程序中,t1 和 t2 都使用相同的列表初始化来初始化对象,但输出的结果却不同。因为对于聚合类型的对象 t1,它可以直接使用列表初始化来初始化对象;对于非聚合类型的对象 t2,它是基于构造函数使用列表初始化来初始化对象

2.2.1 - 聚合类型的定义

  1. 普通数组可以看作是一个聚合类型。

  2. 满足以下条件的类(class、struct、union)可以看作是一个聚合类型:

    • 无基类、无虚函数以及无用户自定义的构造函数

    • 无 private 或 protected 的普通数据成员(即非静态数据成员)

      struct T1
      {
          int _x;
          int _y;
      private:  // 或者 protected
          int _z;
      } t1{ 1, 2, 3 };  // error(类中有私有成员,无法使用列表初始化进行初始化)
      ​
      struct T2
      {
          int _x;
          int _y;
      protected:  // 或者 protected
          static int _z; 
      } t2{ 1, 2 };  // ok
      ​
      int T2::_z = 3;  // 注意:静态数据成员 _z 不能使用列表初始化进行初始化
    • 类中不能有 {} 和 = 直接初始化的非静态数据成员(即就地初始化)

      struct T3
      {
          int _x = 1;
          int _y{ 2 };
      } t3{ 0, 0 };  // error(C++11)

      注意:从 C++14 开始,也可以使用列表初始化来初始化类中使用 {} 和 = 初始化过的非静态数据成员

2.2.2 - 注意事项

聚合类型的定义并非递归的,即当一个类的非静态数据成员是非聚合类型时,这个类也可能是聚合类型

struct T1
{
    int _x;
    int _y;
private:
    int _z;
public:
    T1() : _x(1), _y(2), _z(3) { }
};
​
struct T2
{
    T1 _t1;
    double _d;
};
​
int main()
{
    T2 t2{ {}, 3.14 };
    return 0;
}

可以看到,T1 是非聚合类型,因为它有一个 private 的非静态数据成员,但 T2 依然是一个聚合类型,可以直接使用列表初始化来初始化对象 t2。

注意:使用列表初始化来初始化 t2 的非聚合类型成员 _t1 时,可以直接写一对空的大括号 {},这相当于调用 _t1 的默认构造函数

2.3 - initializer_list

2.3.1 - 基本使用

当编译器看到 { t1, t2, ..., tn } 时,便会生成一个 initializer_list<T> 类型的对象(其中 T 为元素的类型),它关联到一个 array<T, n>

#include <iostream>
using namespace std;
​
int main()
{
    auto il = { 10, 20, 30 };
    cout << typeid(il).name() << endl;  // class std::initializer_list<int>
    return 0;
}

对于聚合类型,编译器会将 array<T, n> 内的元素逐一分解并赋值给被初始化的对象,这相当于为该对象每个字段分别赋值

对于非聚合类型,如果该类存在一个接收 initializer_list<T> 类型的构造函数,则初始化时会将 initializer_list<T> 对象作为一个整体传给构造函数;如果该类不存在这样的构造函数,则 array<T, n> 内的元素会被编译器分解并传给相应的能接收这些参数的构造函数(比如列表中有 2 个元素,就传给带 2 个参数的构造函数,有 3 个元素,就传给带 3 个参数的构造函数,依次类推)

#include <iostream>
#include <vector>
using namespace std;
​
class Test
{
public:
    Test(int) { cout << "Test(int)" << endl; }
​
    Test(int, int) { cout << "Test(int, int)" << endl; }
};
​
int main()
{
    // vector (initializer_list<value_type> il, 
    //      const allocator_type& alloc = allocator_type());
    vector<int> v{ 0, 1, 2, 3, 4 };
    for (const auto& e : v)
    {
        cout << e << " ";
    }
    // 0 1 2 3 4
    cout << endl;
    
    Test t1{ 1 };  // Test(int)
    Test t2{ 1, 2 };  // Test(int, int)
    return 0;
}

2.3.2 - 源码剖析

#include <iostream>
​
template <class T>
class initializer_list
{
public:
    typedef T        value_type;
    typedef const T& reference;  // 说明对象永远为 const,不能被外部修改!
    typedef const T& const_reference;
    typedef size_t   size_type;
    typedef const T* iterator;  // 永远为 const 类型
    typedef const T* const_iterator;
    
private:
    iterator  _M_array; // 用于存放用列表初始化中的元素
    size_type _M_len;   // 元素的个数
​
    // 注意:编译器可以调用 private 的构造函数!!!
    // 构造函数在调用之前,编译会先在外部准备好一个 array,
    // 同时把 array 的地址传入模板,并保存在 _M_array 中
    constexpr initializer_list(const_iterator __a, size_type __l)
        :_M_array(__a), _M_len(__l) {};  // 注意该构造函数被放到 private 中!
    
public:
    // 无参的构造函数
    constexpr initializer_list() : _M_array(0), _M_len(0) {} 
​
    // 用于获取元素的个数
    constexpr size_type size() const noexcept { return _M_len; }
​
    // 获取第一个元素的位置
    constexpr const_iterator begin() const noexcept { return _M_array; }
​
    // 获取最后一个元素的下一个位置
    constexpr const_iterator end() const noexcept
    {
        return begin() + _M_len;
    }
};

让模拟实现的 vector 也支持列表初始化

namespace yzz
{
    template<class T>
    class vector
    {
    public:
        typedef T* iterator;
        typedef const T* const_iterator;
​
        vector(std::initializer_list<T> il) :
            _start(new T[il.size()]),
            _finish(_start + il.size()),
            _end_of_storage(_finish)
        {
            iterator v_it = _start;
            typename std::initializer_list<T>::iterator il_it = il.begin();
            while (il_it != il.end())
            {
                *v_it++ = *il_it++;
            }
        }
        // ... ...
    private:
        iterator _start;
        iterator _finish;
        iterator _end_of_storage;
    };
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1102528.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

使用new创建动态结构

在运行时创建数组优于在编译时创建数组&#xff0c;对于结构&#xff08;同一个结构可以存储多种类型的数据。&#xff09;也是如此。需要在程序运行时为结构分配所需的空间&#xff0c;这也可以使用new运算符来完成。通过使用new&#xff0c;可以创建动态结构。同样&#xff0…

【广州华锐互动】利用AR进行野外地质调查学习,培养学生实践能力

在科技发展的驱动下&#xff0c;AR&#xff08;增强现实&#xff09;技术已经在许多领域中找到了应用&#xff0c;包括医疗、教育、建筑和娱乐等。然而&#xff0c;有一个领域尚未充分利用AR技术的潜力&#xff0c;那就是野外地质调查。通过将AR技术引入到这个传统上需要大量人…

免费:实时 AI 编程助手 Amazon CodeWhisperer

点 &#xff0c;一起程序员弯道超车之路 现已正式推出实时 AI 编程助手 Amazon CodeWhisperer&#xff0c;包括 CodeWhisperer 个人套餐&#xff0c;所有开发人员均可免费使用。最初于去年推出的预览版 CodeWhisperer 让开发人员能够保持专注、高效&#xff0c;帮助他们快速、安…

rabbitMq (2)

RabbitMQ 消息应答与发布 文章目录 1. 消息应答1.2 自动应答1.2 手动应答1.3 代码案例 2. RabbitMQ 持久化2.1 队列持久化2.2 消息持久化 3. 不公平分发4. 预取值分发5. 发布确认5.1 发布确认逻辑5.2 开启发布确认的方法5.3 单个确认发布5.4 批量确认发布5.5 异步确认5.5.1 处理…

【milkv】更新rndis驱动

问题 由于windows升级到了11&#xff0c;导致rndis驱动无法识别到。 解决 打开设备管理器&#xff0c;查看网络适配器&#xff0c;没有更新会显示黄色的图标。 右击选择更新驱动

机器学习基础之《回归与聚类算法(3)—线性回归优化:岭回归》

一、什么是岭回归 其实岭回归就是带L2正则化的线性回归 岭回归&#xff0c;其实也是一种线性回归。只不过在算法建立回归方程时候&#xff0c;加上L2正则化的限制&#xff0c;从而达到解决过拟合的效果 二、API 1、sklearn.linear_model.Ridge(alpha1.0, fit_interceptTrue…

软件测试中bug修正后测试就结束了吗?

一般来说&#xff0c;当 Bug 跟踪系统上所有的 bug 都被关闭了以后&#xff0c;你会感到如释重负&#xff0c;终于可以松一口气了。 当项目成功交付后&#xff0c;你是否感到大脑进入了疲惫期&#xff0c;上网&#xff0c;聊天&#xff0c;写自己感兴趣的小程序&#xff0c;项…

SRS Config 一 基础配置

Config srs 流媒体服务配置官方文档已经很详细了&#xff0c;本文仅记录部分配置过程 srs.conf同级目录下 新建 self.conf 仿照srs.conf 添加基础配置 1 rtmp RTMP是直播的事实标准&#xff0c;这么多年以来一直是使用最广泛的直播协议。 然而Adobe公司没有一直更新RTMP协…

“1688按图搜索商品:拍立淘API,轻松实现高效购物!“

1688按图搜索商品&#xff08;拍立淘&#xff09;API的步骤大致如下&#xff1a; 需要先开放平台注册开发者账号。为每个淘宝应用注册一个应用程序键&#xff0c;登陆密钥。下载1688API的SDK并掌握基本的API基础知识和调用。利用SDK接口和对象&#xff0c;传入AppKey或者必要的…

VScode折叠代码

问题现状 代码看的我很烦&#xff0c; 有大段大段好像没有逻辑意义的部分&#xff0c;像大量的print语句&#xff0c; 想能不能折叠起来 在设置里面找 搜索Folding&#xff0c;找到Show Folding Controls&#xff0c; 换成always吧&#xff0c;一般默认是mouseover&#x…

21-数据结构-内部排序-交换排序

简介&#xff1a;主要根据两个数据进行比较从而交换彼此位置&#xff0c;以此类推&#xff0c;交换完全部。主要有冒泡和快速排序两种。 目录 一、冒泡排序 1.1简介&#xff1a; 1.2代码&#xff1a; 二、快速排序 1.1简介&#xff1a; 1.2代码&#xff1a; 一、冒泡排序…

10.17七段数码管单个多个(部分)

单个数码管的实现 第一种方式 一端并接称为位码&#xff1b;一端分别接收电平信号以控制灯的亮灭&#xff0c;称为段码 8421BCD码转七段数码管段码是将BCD码表示的十进制数转换成七段LED数码管的7个驱动段码&#xff0c; 段码就是LED灯的信号 a为1表示没用到a&#xff0c;a为…

文心一言 VS 讯飞星火 VS chatgpt (115)-- 算法导论10.2 8题

八、用go语言&#xff0c;说明如何在每个元素仅使用一个指针 x.np(而不是通常的两个指针 next和prev)的下实现双向链表。假设所有指针的值都可视为 k 位的整型数&#xff0c;且定义x.npx.next XOR x.prev&#xff0c;即x.nert和x.prev 的 k 位异或。(NIL 的值用0表示。)注意要说…

1数据结构的分类,算法效率的度量

一&#xff0c;数据结构的定义和分类 数据结构&#xff1a;数据之间的关系即数据的逻辑结构&#xff0c;因为要存储到计算机里&#xff0c;所以视为将这个数据的逻辑结构映射到存储器里。即数据因为自身的和其他的数据的关系而在计算机内存储的方式。我们就归类了一些类型。 二…

Idea怎么配置Maven才能优先从本地仓库获取依赖

网上的方法 : 在设置中搜索 Runner ,在VM Option中设置参数 -DarchetypeCataloginternal删除 解压后的依赖包中的 _remote.repositories m2e-lastUpdated.properties *.lastUpdated 文件。 上边都没有效果 最终的解决方法&#xff0c;修改maven配置文件settings.xml 主要两个…

封装一个Element-ui生成一个可行内编辑的表格(vue2项目)

这个封装的是一个供整个项目使用的表格,可多次复用.放在一个全局使用的公共组件文件下. 大致功能介绍,封装自定义指令,点击获得焦点,显示输入框,失去焦点显示文本内容,类型是字典决定类型,图片可以显示图片名还是上传图片 子组件 <script> export default {props: {//生…

6.4 图的存储结构

思维导图&#xff1a; 前言&#xff1a; --- **6.4 图的存储结构** - **核心问题**&#xff1a;由于图的结构复杂性&#xff0c;我们不能仅仅依赖于元素在存储区的物理位置来表示它们之间的关系。 - **邻接矩阵**&#xff1a; - **基本思路**&#xff1a;虽然图没有顺序存…

基于混沌博弈优化的BP神经网络(分类应用) - 附代码

基于混沌博弈优化的BP神经网络&#xff08;分类应用&#xff09; - 附代码 文章目录 基于混沌博弈优化的BP神经网络&#xff08;分类应用&#xff09; - 附代码1.鸢尾花iris数据介绍2.数据集整理3.混沌博弈优化BP神经网络3.1 BP神经网络参数设置3.2 混沌博弈算法应用 4.测试结果…

在Objective-C中使用ASIHTTPRequest发送HTTP请求并获取HTML内容

在网络爬虫开发中&#xff0c;发送HTTP请求并获取目标网站的HTML内容是一项常见任务。通过发送HTTP请求&#xff0c;我们可以模拟浏览器行为&#xff0c;访问网页并获取其中的数据。这些数据可以用于数据分析、信息收集、自动化测试等多种用途。为了实现这个目标&#xff0c;开…

基于堆优化优化的BP神经网络(分类应用) - 附代码

基于堆优化优化的BP神经网络&#xff08;分类应用&#xff09; - 附代码 文章目录 基于堆优化优化的BP神经网络&#xff08;分类应用&#xff09; - 附代码1.鸢尾花iris数据介绍2.数据集整理3.堆优化优化BP神经网络3.1 BP神经网络参数设置3.2 堆优化算法应用 4.测试结果&#x…