【C++ 学习 ㉘】- 详解 C++11 的列表初始化
目录
一、C++11 简介
二、列表初始化
2.1 - 统一初始化
2.2 - 列表初始化的使用细节
2.2.1 - 聚合类型的定义
2.2.2 - 注意事项
2.3 - initializer_list
2.3.1 - 基本使用
2.3.2 - 源码剖析
一、C++11 简介
-
1998 年,C++ 标准委员会发布了第一版 C++ 标准,即 C++98 标准,并计划以后每 5 年视实际需要更新一次标准。
所谓标准,即明确 C++ 代码的编写规范,所有的 C++ 程序员都应遵守此标准。
-
2003 年,C++ 标准委员会发布了第二版 C++ 标准,即 C++03 标准,但由于 C++03 仅修复了一些 C++98 中存在的漏洞,并未修改核心语法,因此人们习惯将这两个标准合称为 C++98/03 标准。
-
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;
}
a3、a4 使用了 C++11 的列表初始化来初始化对象,效果如同 a1 的直接初始化。
至于 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, 520cout << t2._x << ", " << t2._y << endl; // 1314, 1314return 0;
}
在上面的程序中,t1 和 t2 都使用相同的列表初始化来初始化对象,但输出的结果却不同。因为对于聚合类型的对象 t1,它可以直接使用列表初始化来初始化对象;对于非聚合类型的对象 t2,它是基于构造函数使用列表初始化来初始化对象。
2.2.1 - 聚合类型的定义
-
普通数组可以看作是一个聚合类型。
-
满足以下条件的类(class、struct、union)可以看作是一个聚合类型:
-
无基类、无虚函数以及无用户自定义的构造函数。
-
无 private 或 protected 的普通数据成员(即非静态数据成员)。
struct T1 {int _x;int _y; private: // 或者 protectedint _z; } t1{ 1, 2, 3 }; // error(类中有私有成员,无法使用列表初始化进行初始化) struct T2 {int _x;int _y; protected: // 或者 protectedstatic 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 4cout << 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;};
}
相关文章:

【C++ 学习 ㉘】- 详解 C++11 的列表初始化
目录 一、C11 简介 二、列表初始化 2.1 - 统一初始化 2.2 - 列表初始化的使用细节 2.2.1 - 聚合类型的定义 2.2.2 - 注意事项 2.3 - initializer_list 2.3.1 - 基本使用 2.3.2 - 源码剖析 一、C11 简介 1998 年,C 标准委员会发布了第一版 C 标准࿰…...

OpenCV12-图像卷积
OpenCV12-图像卷积 图像卷积 图像卷积 OpenCV中提供了filt2D()函数用于实现图像和卷积模板之间的卷积运算: void filter2D(InputArray src, // 输入图像OutputArray dst, // 输出图像int ddepth, // 输出图像数据类型(深度)ÿ…...

MVCC与BufferPool缓存机制
MVCC多版本并发控制机制 Mysql在可重复读隔离级别下如何保证事务较高的隔离性,我们上节课给大家演示过,同样的sql查询语句在一个事务里多次执行查询结果相同,就算其它事务对数据有修改也不会影响当前事务sql语句的查询结果。 这个隔离性就是…...

POI、Easy Excel操作Excel
文章目录 1.常用的场景2.基本功能3.Excel在Java中是一个对象4. 简单的写(07版本(.xlsx)Excel)大文件写HSSF大文件写XSSF大文件写SXSSF 5. Excel读5.1 读取遇到类型转化问题该怎么解决5.2 遇到Excel公式怎么办 6. Easy Excel6.1简单…...

网络安全(黑客)自学方向
每年报考网络安全专业的人数很多,但不少同学听说千万别学网络安全,害怕网络安全专业很难就业。下面就带大家深入了解一下网络安全专业毕业后可以干什么,包括网络安全专业的就业前景和方向等。 随着信息化时代的到来,网络安全行业…...

react写一个简单的3d滚轮picker组件
1. TreeDPicker.tsx文件 原理就不想赘述了, 想了解的话, 网址在: 使用vue写一个picker插件,使用3d滚轮的原理_vue3中支持3d picker选择器插件-CSDN博客 import React, { useEffect, useRef, Ref, useState } from "react"; import Animate from "../utils/an…...

Compose竖向列表LazyColumn
基础列表一 LazyColumn组件中用items加载数据,rememberLazyListState()结合rememberCoroutineScope()实现返回顶部。 /*** 基础列表一*/ Composable fun Items() {Box(modifier Modifier.fillMaxSize()) {val context LocalContext.currentval dataList arrayLi…...

6.自定义相机控制器
愿你出走半生,归来仍是少年! Cesium For Unity自带的Dynamic Camera,拥有优秀的动态展示效果,但是其对于场景的交互方式用起来不是很舒服。 通过模仿Cesium JS 的交互方式,实现在Unity中的交互: 通过鼠标左键拖拽实现场景平移通过…...

一文带你GO语言入门
什么是go语言? Go语言(又称Golang)是Google开发的一种静态强类型、编译型、并发型,并具有垃圾回收功能的编程语言。Go语言的主要特点包括:- 简洁和简单 - 语法简单明快,易于学习和使用 特点 高效 编译速度快,执行效率高 并发支持 原生支持并发,利用goroutine实现高效的并发…...

前后端小项目链接
1.vue的创建 vue的项目创建 1.1 vue create vue_name 1.2 Babel Router(路由) CSS Pre-processors 路由可通过:npm i vue-router3.5.2 -S 下载 1.3less 1.4 In dedicated config files 1.5 启动命令:npm run serve 端口号在vue.config。js中配置 devS…...

编辑器功能:用一个快捷键来【锁定】或【解开】Inspector面板
一、需求 我有一个脚本,上面暴露了许多参数,我要在场景中拖物体给它进行配置。 如果不锁定Inspector面板的话,每次点击物体后,Inspector的内容就是刚点击的物体的内容,而不是挂载脚本的参数面板。 二、 解决 &…...

Vue 网络处理 - axios 异步请求的使用,请求响应拦截器(最佳实践)
目录 一、axiox 1.1、axios 简介 1.2、axios 基本使用 1.2.1、下载核心 js 文件. 1.2.2、发送 GET 异步请求 1.2.3、发送 POST 异步请求 1.2.4、发送 GET、POST 请求最佳实践 1.3、请求响应拦截器 1.3.1、拦截器解释 1.3.2、请求拦截器的使用 1.3.3、响应拦截器的使…...

关于W5500网卡使用过程的部分问题记录
某个项目中用到了W5500这种自带网络协议栈的网卡芯片,由于该项目开发时间很紧,就临时网上买了一些模块拼凑到了一套系统,经过验证果真这种拼积木的方法只能用在学生实验开发中,真不能拿来做工程应用,硬件太不稳定很容易…...

Unity DOTS World Entity ArchType Component EntityManager System概述
最近DOTS终于发布了正式的版本, 我们来分享以下DOTS里面地几个关键概念,方便大家上手学习掌握Unity DOTS开发。 Unity DOTS 中所有的Entities 都是被放到World世界中。每个Entity在它所在的World里面有唯一不同的ID号来区分。DOTS项目中可以同时有多个World。每个W…...

最详细STM32,cubeMX 点亮 led
这篇文章将详细介绍 如何在 stm32103 板子上点亮一个LED. 文章目录 前言一、开发环境搭建。二、LED 原理图解读三、什么是 GPIO四、cubeMX 配置工程五、解读 cubeMX 生成的代码六、延时函数七、控制引脚状态函数点亮 LED 八、GPIO 的工作模式九、为什么使用推挽输出驱动 LED总结…...

论文阅读:Image-to-Lidar Self-Supervised Distillation for Autonomous Driving Data
目录 摘要 Motivation 整体架构流程 技术细节 雷达和图像数据的同步 小结 论文地址: [2203.16258] Image-to-Lidar Self-Supervised Distillation for Autonomous Driving Data (arxiv.org) 论文代码:GitHub - valeoai/SLidR: Official PyTorch implementati…...

前端版本控制工具,常见的Git 和SVN
目录 前言GitGit简介Git的优势Git常用指令常见的Git服务 SVN (Subversion)SVN简介SVN的优势SVN常用指令SVN与Git的区别 👍 点赞,你的认可是我创作的动力! ⭐️ 收藏,你的青睐是我努力的方向! ✏️ 评论,你…...

C++ —— Tinyxml2在Vs2017下相关使用2(较文1更复杂,附源码)
相关链接 C —— Tinyxml2在Vs2017下相关使用1(附源码) tinyxml2简介 TinyXML2是一个简单,小巧,高效,CXML解析器,可以很容易地集成到其他程序中。TinyXML-2解析一个XML文档,并从中构建一个 可以…...

阿里内推强推的并发编程学习笔记,原理+实战+面试题,面面俱到!
并发编程 谈到并发编程,可能很多人都有过经验,甚至比我了解的更多。 那么并发与并行的区别又是什么? 并发编程是编程中的核心问题,实践中,当人们希望利用计算机处理一些现实世界问题,以及希望同时处理多…...

域名注册查询流程
域名注册查询怎么查域名是否被注册?域名注册查询如何查域名的过期时间和注册商?域名注册查询用什么工具?下面是关于域名注册查询流程介绍。 1、域名注册查询可以用什么工具? 这里可以使用聚查工具,聚查包括:whois 查询、建站历史查询、反链查询、P…...

【Linux学习笔记】代码编辑工具vim
1. vim工具基本模式的转换2. vim命令模式下的各种编辑命令2.1. 光标行定位2.2. 光标自由定位2.3. 复制粘贴2.4. 删除2.5. 文本的大小写替换2.6. 文本的替换2.7. 文本的前删后删2.8. 撤销操作 3. vim底行模式下的命令3.1. 设置行号与取消设置行号3.2. 分屏操作3.3. 在不退出vim的…...

Android Boring SSL
前期设置 SSLContext.getInstance(“TLS”)SSLContext.init()SSLContext.getSocketFactory()SSLSocketFactory.createSocket()NativeSsl.newInstance()BioWrapper 的创建ConscryptEngineSocket.startHandshake() TLS协商 state_start_connect(TLS)state_enter_early_data(TLS)s…...

中国人民大学与加拿大女王大学金融硕士项目:开启你的金融精英之路
在全球化的今天,金融行业的发展日新月异,对金融人才的需求也日益增长。为了满足这一需求,中国人民大学与加拿大女王大学联合推出了金融硕士项目,旨在培养具有国际视野、专业素养和创新能力的金融精英。 这一开创性的项目将两大世…...

HashSet编程小案例,控制生日和姓名。重写HashCode
Java编程: 定义员工Employee类,该类包含:private成员属性name,sal,birthday(MyDate类型), 其中birthday为MyDate类型(属性包括:year,month,day), 要求&…...

虚幻阴影整理
虚拟阴影贴图(VSM)是一种全新的阴影贴图方法,可以提供稳定的高分辨率阴影。通过与虚幻引擎5的Nanite虚拟几何体、Lumen全局光照和反射以及世界分区功能结合使用,它能够实现电影级的品质效果,为大型开放场景提供光照。 …...

MySQL数据库(一)
数据库 —— 基础 1. 数据库 DataBase 数据库管理系统 2. SQL语言2.1 DDL数据定义语言2.1.1 数据库基础操作2.1.2 数据表基础操作2.1.3 字段基础操作 2.2 DML表记录管理2.2.1 插入数据INSERT2.2.2 更新数据UPDATE2.2.3 删除数据DELETE 3. SQL数据类型3.1 数值类型3.1.1 整数类型…...

C++11 新特性
C11 新特性 C11 新特性统一的列表初始化声明auto 关键字decltype 关键字nullptr 关键字 关键字 using使用 using 在子类中引用基类的成员使用 using 关键字定义类型别名 范围-based for 循环右值引用和移动语义左值引用和右值引用右值引用使用场景和意义完美转发 lambda表达式移…...

排查手机应用app微信登录问题不跳转失败原因汇总及其解决方案
经过最近我发的文章,我个人觉得解决了不少小问题,因为最近很小白的问题已经没有人私聊问我了,我总结了一下排查手机应用app微信登录问题不跳转失败的原因汇总及其解决方案在这篇文章中,分析微信登录不跳转的原因,并提供解决方案。希望通过这篇文章,能够帮助大家顺利解决这…...

软考高级系统架构设计师系列之:数学与经济管理
软考高级系统架构设计师系列之:数学与经济管理 一、数学与经济管理二、图论应用-最小生成树三、图论应用-最短路径四、图论应用-网络与最大流量五、运筹方法-线性规划六、运筹方法-动态规划七、运筹方法-转移矩阵八、运筹方法-排队论九、运筹方法-决策-不确定决策十、运筹方法…...

基于Scrapyd与Gerapy部署scrapy爬虫方案【可用于分布式爬虫部署】
scrapyd部署爬虫 Scrapyd 是一个基于 Scrapy 的开源项目,它提供了一个简单的方式来部署、运行和监控 Scrapy 爬虫。它是一个用于集成 Scrapy 爬虫到分布式架构中的工具,允许您在分布式环境中运行爬虫,并提供了一组 Web API,用于管…...