首页/新闻资讯/正文详情

C++11 核心讲解:列表初始化,右值引用和移动语义

发布时间:2026/9/27 11:00:35 来源:云帆数科 栏目:资讯中心
C++11 核心讲解:列表初始化,右值引用和移动语义
目录一.C11的发展历史二.C列表初始化2.1C98传统的{}2.2 C11中的{}2.3C中的std::initializer_list三、右值引用和移动语义3.1 左值和右值3.2 左值引用和右值引用3.3 引用延长生命周期3.4 左值和右值的参数匹配3.5 右值引用和移动语义的使用场景3.5.1 左值引用主要使用场景回顾3.5.2 移动构造和移动赋值3.5.3 右值引用和移动语义解决传值返回问题一.C11的发展历史C11 是 C 的第二个主要版本并且是从 C98 起的最重要更新。它引入了大量更改标准化了既有实践并改进了对 C 程序员可用的抽象。在它最终由 ISO 在 2011 年 8 月 12 日采纳前人们曾使用名称 “C0x”因为它曾被期待在 2010 年之前发布。C03 与 C11 期间花了 8 年时间故而这是迄今为止最长的版本间隔。从那时起C 有规律地每 3 年更新一次。二.C列表初始化2.1C98传统的{}C98中⼀般数组和结构体可以⽤{}进⾏初始化。2.2 C11中的{}C11 以后想统一初始化方式试图实现一切对象皆可用 {} 初始化{} 初始化也叫做列表初始化注意和构造函数那里的初始化进行区分构造函数那里的{}叫做初始化列表和这里是没有关联关系的。内置类型支持自定义类型也支持自定义类型本质是类型转换中间会产生临时对象最后优化了以后变成直接构造。{} 初始化的过程中可以省略掉 C11 列表初始化的本意是想实现一个大统一的初始化方式其次他在有些场景下带来的不少便利如容器 push/inset 多参数构造的对象时{} 初始化会很方便下面讲的左值右值之类的后面会将这里只是让大家看一下三种构造的区别1.v1.push_back(d1); // 有名对象d1是有名左值对象。参数d1是左值匹配push_back(const Date)vector 获取d1的只读引用在 vector 堆空间开辟一块 Date 内存调用 Date 的拷贝构造函数以d1为模板复制出新对象存入容器执行完毕容器内是独立副本d1继续存在不受影响。2.v1.push_back(Date(2026, 8, 5)); // 匿名对象Date(2026,8,5)是临时匿名对象属于右值。C11 及之后现代标准执行Date(2026,8,5)在栈上创建临时匿名对象临时对象是右值匹配重载push_back(Date)vector 在堆上分配空间调用 Date 的移动构造函数把临时对象资源 “转移” 进容器语句结束栈上临时对象被销毁资源已经转移析构无事可做。3.v1.push_back({ 2026,8,15 }); // 花括号初始化列表这是列表初始化braced-init-list分两层理解{2026,8,15}是不带类型的初始化列表编译器尝试用这组参数构造一个临时Date对象等价于Date{2026,8,15}生成临时 Date 右值后续流程和上面匿名对象完全一致匹配右值版本push_back(Date)调用移动构造将对象移入 vector。写法是否产生临时对象最终调用构造push_back(d1)无临时拷贝构造push_back(Date(y,m,d))栈上临时对象移动构造C11push_back({y,m,d})栈上临时对象移动构造C11emplace_back(y,m,d)无临时直接在容器内构造2.3C中的std::initializer_list上⾯的初始化已经很⽅便但是对象容器初始化还是不太⽅便⽐如⼀个vector对象我想⽤N个 值去构造初始化那么我们得实现很多个构造函数才能⽀持 vector v1 {1,2,3};vector v2 {1,2,3,4,5};C11库中提出了⼀个std::initializer_list的类 auto il { 10, 20, 30 }; // the type of il is an initializer_list 这个类的本质是底层开⼀个数组将数据拷⻉ 过来std::initializer_list内部有两个指针分别指向数组的开始和结束。这是他的⽂档initializer_liststd::initializer_list⽀持迭代器遍历。容器⽀持⼀个std::initializer_list的构造函数也就⽀持任意多个值构成的 初始化。STL中的容器⽀持任意多个值构成的 {x1,x2,x3...} 进⾏ {x1,x2,x3...} 进⾏初始化就是通过 std::initializer_list的构造函数⽀持的。三、右值引用和移动语义C98 的语法中就有引用的语法而 C11 中新增了的右值引用语法特性C11 之后我们之前学习的引用就叫做左值引用。无论左值引用还是右值引用都是给对象取别名。3.1 左值和右值左值是一个表示数据的表达式 (如变量名或解引用的指针甚至可以是一个函数调用所指就是函数调用的返回值)一般是有持久状态存储在内存中我们可以获取它的地址左值可以出现在赋值符号的左边也可以出现在赋值符号右边。定义时 const 修饰符后的左值不能给他赋值不严谨但是可以取它的地址。3.2 左值引用和右值引用Type r1 x; Type rr1 y; 第一个语句就是左值引用左值引用就是给左值取别名第二个就是右值引用同样的道理右值引用就是给右值取别名。左值引用不能直接引用右值但是const左值引用可以引用右值右值引用不能直接引用左值但是右值引用可以引用move(左值)template class T typename remove_reference T ::type move (T arg);move是库里面的一个函数模板本质内部是进行强制类型转换当然他还涉及一些引用折叠的知识这个我们后面会细讲。需要注意的是变量表达式都是左值属性也就意味着一个右值被右值引用绑定后右值引用变量变量表达式的属性是左值表达式类型cout 行为iint*打印内存地址s[0]char*打印字符串内容pint*int*打印内存地址3.3 引用延长生命周期C 里const 左值引用 和 右值引用都能把临时对象的生命周期从 “当前语句” 延长到 “引用的作用域结束”。区别只在于能不能修改这个对象。像 s1 s1 这种表达式会返回一个临时的 std::string 对象其是一个纯右值rvalue用完即毁默认生命周期只到当前语句结束默认情况下不能直接修改它比如 (s1 s1) “Test” 会报错。r3 是一个右值引用右值对象是没办法直接修改的但它是一个有名字的变量C 里有名字的变量都是左值不管它是什么类型的引用所以 r3 本身是左值可以被赋值、被修改也可以被取地址而 r3 绑定的是临时对象所以通过 r3 就能修改这个原本无法直接修改的临时对象。3.4 左值和右值的参数匹配C98 中我们实现一个 const 左值引用作为参数的函数那么实参传递左值和右值都可以匹配。C11 以后分别重载左值引用、const 左值引用、右值引用作为形参的 f 函数那么实参是左值会匹配 f (左值引用)实参是 const 左值会匹配 f (const 左值引用)实参是右值会匹配 f (右值引用)。右值引用变量在用于表达式时属性是左值这个设计这里会感觉很怪下面我们讲右值引用的使用场景时就能体会这样设计的价值了3.5 右值引用和移动语义的使用场景3.5.1 左值引用主要使用场景回顾左值引用主要使用场景是在函数中左值引用传参和左值引用传返回值时减少拷贝同时还可以修改实参和修改返回对象的价值。左值引用已经解决大多数场景的拷贝效率问题但是有些场景不能使用传左值引用返回如 addStrings 和 generate 函数C98 中的解决方案只能是被迫使用输出型参数解决。两次拷贝的代价太大所以后面引入了移动构造和移动赋值3.5.2 移动构造和移动赋值移动构造函数是一种构造函数类似拷贝构造函数它是之前拷贝构造的函数重载移动构造函数要求第一个参数是该类类型的引用但是不同的是要求这个参数是右值引用如果还有其他参数额外的参数必须有缺省值。移动赋值是一个赋值运算符的重载他跟拷贝赋值构成函数重载类似拷贝赋值函数移动赋值函数要求第一个参数是该类类型的引用但是不同的是要求这个参数是右值引用。对于像 string/vector 这样的深拷贝的类或者包含深拷贝的成员变量的类移动构造和移动赋值才有意义因为移动构造和移动赋值的第一个参数都是右值引用的类型他的本质是要 “窃取” 引用的右值对象的资源而不是像拷贝构造和拷贝赋值那样去拷贝资源从提高效率。下面的 bit::string 样例实现了移动构造和移动赋值我们需要结合场景理解3.5.3 右值引用和移动语义解决传值返回问题这里用用命名空间与库里面区分是为了方便观察调用的构造.移动构造等#includeiostream #includeassert.h #includestring.h #includealgorithm using namespace std; namespace Jam { class string { public: typedef char* iterator; typedef const char* const_iterator; iterator begin() { return _str; } iterator end() { return _str _size; } const_iterator begin() const { return _str; } const_iterator end() const { return _str _size; } string(const char* str ) :_size(strlen(str)) , _capacity(_size) { cout string(char* str)-构造 endl; _str new char[_capacity 1]; strcpy(_str, str); } void swap(string s) { ::swap(_str, s._str); ::swap(_size, s._size); ::swap(_capacity, s._capacity); } // 拷贝构造 string(const string s) { cout string(const string s) -- 拷贝构造 endl; reserve(s._capacity); for (auto ch : s) { push_back(ch); } } // 移动构造 string(string s) { cout string(string s) -- 移动构造 endl; swap(s); } string operator(const string s) { cout string operator(const string s) -- 拷贝赋值 endl; if (this ! s) { _str[0] \0; _size 0; reserve(s._capacity); for (auto ch : s) { push_back(ch); } } return *this; } // 移动赋值 string operator(string s) { cout string operator(string s) -- 移动赋值 endl; swap(s); return *this; } ~string() { cout ~string() -- 析构 endl; delete[] _str; _str nullptr; } char operator[](size_t pos) { assert(pos _size); return _str[pos]; } void reserve(size_t n) { if (n _capacity) { char* tmp new char[n 1]; if (_str) { strcpy(tmp, _str); delete[] _str; } _str tmp; _capacity n; } } void push_back(char ch) { if (_size _capacity) { size_t newcapacity _capacity 0 ? 4 : _capacity * 2; reserve(newcapacity); } _str[_size] ch; _size; _str[_size] \0; } string operator(char ch) { push_back(ch); return *this; } const char* c_str() const { return _str; } size_t size() const { return _size; } private: char* _str nullptr; size_t _size 0; size_t _capacity 0; }; // 传值返回需要拷贝 string addStrings(string num1, string num2) { string str; int end1 num1.size() - 1, end2 num2.size() - 1; // 进位 int next 0; while (end1 0 || end2 0) { int val1 end1 0 ? num1[end1--] - 0 : 0; int val2 end2 0 ? num2[end2--] - 0 : 0; int ret val1 val2 next; next ret / 10; ret ret % 10; str (0 ret); } if (next 1) str 1; reverse(str.begin(), str.end()); return str; } } int main() { Jam::string ret yunze::addStrings(11111, 2222); }也可以看到现代编译器的极致优化就相当于str是ret的别名了二者地址都指向的是一块空间

相关推荐

嵌入式偶发故障排查:串口、蓝牙与烧录问题定位指南
嵌入式偶发故障排查:串口、蓝牙与烧录问题定位指南

做过嵌入式或者软硬件联调的朋友,一定都遇到过这种场景:手头设备功能验收的时候怎么测都正常,可一到客户现场或者量产抽测,就时不时冒出一个莫名其妙的毛病——串口偶尔读不到数据、蓝牙用着用着就断开、烧录的时候十块板子总有那… · 2026/9/27 11:00:29

基于html做电商网站论文被黑挂马?3招用免费工具自查
基于html做电商网站论文被黑挂马?3招用免费工具自查

基于html做电商网站论文被黑挂马?3招用免费工具自查 网站突然打不开,或者打开全是赌博广告,后台密码改了也进不去,这种“网站被黑挂马”的深夜惊魂时刻,是每个做前端和全栈开发者的噩梦。如果你正在写《基于html做电商网站》的毕业论文,或者刚… · 2026/9/27 11:00:29

Longhorn v1.8.1 发布深度解析:升级路径、稳定性修复与备份/V2 数据引擎问题清单
Longhorn v1.8.1 发布深度解析:升级路径、稳定性修复与备份/V2 数据引擎问题清单

云原生存储高可用容器编排 【免费下载链接】longhorn Cloud-Native distributed storage built on and for Kubernetes 项目地址: https://gitcode.com/gh_mirrors/lo/longhorn 点击查看 免费下载 Longhorn v1.8.1 是 Longhorn 1.8 分支的第二个补丁版本&#xff0… · 2026/9/27 11:00:23

深圳网站建设乐云践新怎么选?3步避坑指南
深圳网站建设乐云践新怎么选?3步避坑指南

深圳网站建设乐云践新怎么选?3步避坑指南 找深圳建站公司,最怕遇到“低价引流,后期加钱”的套路。很多老板花了大几万,最后拿到的网站不仅加载慢,还搜不到关键词。其实 深圳网站建设乐云践新怎么选 ,核心不在比价格,而在看交付标准。… · 2026/9/27 11:57:35

wordpress版权所有图解步骤
wordpress版权所有图解步骤

告别模板丑站:WordPress版权页最佳实践与实操指南 还在被那些千篇一律、配色刺眼的模板网站折磨?看着后台生成的默认页面,你是不是也觉得“太丑了、不够用”,根本拿不出手给客户看?别急,这正是新手最容易踩的坑。其实,一个专业的企业站,不仅… · 2026/9/27 11:57:35

AI高效修Bug:5步搞定代码难题,TaoToken统一Key接入实战
AI高效修Bug:5步搞定代码难题,TaoToken统一Key接入实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/27 11:57:29

避坑指南:网络推广方案策划报告怎么写才不翻车?5个注意事项
避坑指南:网络推广方案策划报告怎么写才不翻车?5个注意事项

避坑指南:网络推广方案策划报告怎么写才不翻车?5个注意事项 做建站和运维的兄弟,是不是经常被老板或客户怼:“这网站怎么这么丑?模板改改就能用,还要我花大钱?” 模板网站太丑不够用 ,这是咱们这行最真实的痛。… · 2026/9/27 11:57:23

Prompt提示词与代码项目结构图:用TaoToken统一Key优化学习路径,提高学习效率
Prompt提示词与代码项目结构图:用TaoToken统一Key优化学习路径,提高学习效率

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/27 11:57:17

2026年老师都在用的英语听力平台,实测这5个
2026年老师都在用的英语听力平台,实测这5个

核心要点:英语听力平台到2026年,老师挑工具的逻辑变了:素材多不多只是基础,能不能分层放音、能不能把错题自动收上来、能不能生成可读的学情报告,才是每天要面对的。统一语速和手动错题本,是听力训练里最耗… · 2026/9/27 11:57:17

MATLAB雷达信号脉冲压缩仿真:LFM线性调频、匹配滤波与距离分辨率实现
MATLAB雷达信号脉冲压缩仿真:LFM线性调频、匹配滤波与距离分辨率实现

简介:这套Matlab仿真工具完整呈现雷达信号脉冲压缩过程,从线性调频(LFM)信号生成、目标回波仿真到匹配滤波压缩处理均有可运行代码支撑,面向电子信息工程、计算机、数学等专业学生,适用于课程设计、期末大作… · 2026/9/27 0:00:01

汕头网站建设制作厂家避坑指南:5大注意事项救急
汕头网站建设制作厂家避坑指南:5大注意事项救急

汕头网站建设制作厂家避坑指南:5大注意事项救急 改个需求建站公司拖一周,这种憋屈事我见得太多了。 很多汕头老板找本地建站团队,签合同前看着方案挺美,一上线就变脸。 今天不聊虚的,直接拆解找 汕头网站建设制作厂家 时的5个核心 注意事项… · 2026/9/27 0:00:01

多模态虚假新闻检测实战:BERT+ResNet双塔与对比学习
多模态虚假新闻检测实战:BERT+ResNet双塔与对比学习

简介:基于PyTorch的多模态虚假新闻检测项目完整代码包,面向自然语言处理与计算机视觉交叉方向的开发者、科研人员及毕业设计选题者,解决社交媒体中文本与图像联合识别虚假新闻的问题。系统以BERT预训练模型提取文本语义特征,以Res… · 2026/9/27 0:00:01

MATLAB雷达信号脉冲压缩仿真:LFM线性调频、匹配滤波与距离分辨率实现
MATLAB雷达信号脉冲压缩仿真:LFM线性调频、匹配滤波与距离分辨率实现

简介:这套Matlab仿真工具完整呈现雷达信号脉冲压缩过程,从线性调频(LFM)信号生成、目标回波仿真到匹配滤波压缩处理均有可运行代码支撑,面向电子信息工程、计算机、数学等专业学生,适用于课程设计、期末大作… · 2026/9/27 0:00:01

汕头网站建设制作厂家避坑指南:5大注意事项救急
汕头网站建设制作厂家避坑指南:5大注意事项救急

汕头网站建设制作厂家避坑指南:5大注意事项救急 改个需求建站公司拖一周,这种憋屈事我见得太多了。 很多汕头老板找本地建站团队,签合同前看着方案挺美,一上线就变脸。 今天不聊虚的,直接拆解找 汕头网站建设制作厂家 时的5个核心 注意事项… · 2026/9/27 0:00:01

多模态虚假新闻检测实战:BERT+ResNet双塔与对比学习
多模态虚假新闻检测实战:BERT+ResNet双塔与对比学习

简介:基于PyTorch的多模态虚假新闻检测项目完整代码包,面向自然语言处理与计算机视觉交叉方向的开发者、科研人员及毕业设计选题者,解决社交媒体中文本与图像联合识别虚假新闻的问题。系统以BERT预训练模型提取文本语义特征,以Res… · 2026/9/27 0:00:01

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码