news 2026/8/23 13:55:15

C++:C++11

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
C++:C++11

前言:前面涉及C++11的知识点我们补充讲解过,现在这篇博客我们正式讲解C++11。

我尽量活成我想成为的模样,而不是某些人口中的‘他’。

我们每个人都在跟自己的业力对抗,都想努力变好,可是这个世界本身就是矛盾的。

愿吾之愿力能护持汝生生世世,不被世俗沉沦,看破诸法实相

C++11简介

2003C++标准委员会曾经提交了一份技术勘误表(简称TC1),使得C++03这个名字已经取代了 C++98称为C++11之前的最新C++标准名称。不过由于C++03(TC1)主要是对C++98标准中的漏洞 进行修复,语言的核心部分则没有改动,因此人们习惯性的把两个标准合并称为C++98/03标准。
C++0xC++11C++标准10年磨一剑,第二个真正意义上的标准珊珊来迟。相比C++98/03C++11则带来了数量可观的变化,其中包含了约140个新特性,以及对C++03标准中600个缺陷的修正,这使得C++11更像是从C++98/03中孕育出的一种新语言。相比较而言,C++11能更好地用于系统开发和库开发、语法更加泛华和简单化、更加稳定和安全,不仅功能更强大,而且能提升程序员的开发效率,公司实际项目开发中也用得比较多,所以我们要作为一个重点去学习C++11增加的语法特性非常篇幅非常多,我们这里没办法一 一讲解,所以本节课程主要讲解实际中比较实用的语法。

统一的列表初始化

{}初始化

C++98中,标准允许使用花括号{}对数组或者结构体元素进行统一的列表初始值设定。比如:

C++11扩大了用大括号括起的列表(初始化列表)的使用范围,使其可用于所有的内置类型和用户自
定义的类型,使用初始化列表时,可添加等号(=),也可不添加

 创建对象时也可以使用列表初始化方式调用构造函数初始化

class Date { public: Date(int year, int month, int day) :_year(year) ,_month(month) ,_day(day) { cout << "Date(int year, int month, int day)" << endl; } private: int _year; int _month; int _day; }; int main() { Date d1(2022, 1, 1); // old style // C++11支持的列表初始化,这里会调用构造函数初始化 Date d2{ 2022, 1, 2 }; //直接调用构造 Date d3 = { 2022, 1, 3 }; //这里先调用构造生成一个初始化的临时对象,然后拷贝构造给对象 return 0; }

单参数列表初始化可省略列表

class A { public: //explicit A(int x, int y) explicit可以防止隐式类型转换,使列表初始化失效 A(int x, int y) :_x(x) ,_y(y) {} A(int x) :_x(x) ,_y(x) {} private: int _x; int _y; }; int main() { A aa1 = 1; A aa2={1}; //都是先调用构造生成临时对象,然后拷贝构造 return 0; }

赋值重载运算符也支持使用列表,A a,a={1}或a=1,先构造临时对象然后调用赋值运算符。

std::initializer_list

std::initializer_list是什么类型

std::initializer_list使用场景
std::initializer_list一般是作为构造函数的参数,C++11STL中的不少容器就增加
std::initializer_list作为参数的构造函数,这样初始化容器对象就更方便了。也可以作为operator=
的参数,这样就可以用大括号赋值。没有 initializer_list 赋值重载: a={1}  → 构造临时对象,再拷贝赋值。有 initializer_list 赋值重载: a={1}  → 直接接收列表,无临时对象。
int main() { vector<int> v = { 1,2,3,4 }; //vector<int> v{ 1,2,3,4 }; //vector<int> v({1,2,3,4}); list<int> lt = { 1,2 }; // 1.这里{"sort", "排序"}会先初始化构造一个pair对象 // 2.initializer_list<pair>的构造 map<string, string> dict = { {"sort", "排序"}, {"insert", "插入"} }; // 使用大括号对容器赋值 v = {10, 20, 30}; return 0; }
让模拟实现的vector也支持{}初始化和赋值
namespace bit { template<class T> class vector { public:     typedef T* iterator;     vector(initializer_list<T> l)     {         _start = new T[l.size()];         _finish = _start + l.size();         _endofstorage = _start + l.size();         iterator vit = _start;         typename initializer_list<T>::iterator lit = l.begin();         while (lit != l.end())         {             *vit++ = *lit++;         }         //for (auto e : l)         //   *vit++ = e;     }     vector<T>& operator=(initializer_list<T> l) {         vector<T> tmp(l);         std::swap(_start, tmp._start);         std::swap(_finish, tmp._finish);         std::swap(_endofstorage, tmp._endofstorage);         return *this;     } private:     iterator _start;     iterator _finish;     iterator _endofstorage; }; }

声明

c++11提供了多种简化声明的方式,尤其是在使用模板时。

auto

C++98auto是一个存储类型的说明符,表明变量是局部自动存储类型,但是局部域中定义局
部的变量默认就是自动存储类型,所以auto就没什么价值了。C++11中废弃auto原来的用法,将
其用于实现自动类型推断。这样要求必须进行显示初始化,让编译器将定义对象的类型设置为初
始化值的类型。具体看前文。

decltype

关键字decltype将变量的类型声明为表达式指定的类型。
template<class T> class B { public: T* New(int n) { return new T[n]; } }; auto func1() { list<int> lt; auto ret = lt.begin(); return ret; } int main() { list<int>::iterator it1; // typeid推出时一个单纯的字符串 cout << typeid(it1).name() << endl; // // 不能用来定义对象 // //typeid(it1).name() it2; // 可以用来定义对象 decltype(it1) it2; cout << typeid(it2).name() << endl; auto it3 = it1; cout << typeid(it3).name() << endl; auto ret3 = func1(); B<decltype(ret3)> bb1; B<decltype(it3)> bb2; //B<std::list<int>::iterator> bb2; // auto和decltype有些地方增加代码读起来难度 return 0; }

nullptr

由于C++NULL被定义成字面量0,这样就可能回带来一些问题,因为0既能指针常量,又能表示 整形常量。所以出于清晰和安全的角度考虑,C++11中新增了nullptr,用于表示空指针

范围for循环

在前文我们已经具体讲解了,这里我们补充一点

int main() { map<string, string> dict2 = { {"sort", "排序"}, {"insert", "插入"} }; for (auto& [x,y] : dict2) { cout << x << ":" << y << endl; //x += '1'; y += '2'; } for (auto [x, y] : dict2) { cout << x << ":" << y << endl; } pair<string, string> kv1 = { "sort", "排序" }; auto [x, y] = kv1; return 0; }

智能指针

这个我们在智能指针课程中已经会进行了非常详细的讲解,这里就不进行讲解了

STL中一些变化

新容器
用橘色圈起来是C++11中的一些几个新容器,但是实际最有用的是unordered_map和 unordered_set。这两个我们前面已经进行了非常详细的讲解,其他的大家了解一下即可。

容器中的一些新方法
如果我们再细细去看会发现基本每个容器中都增加了一些C++11的方法,但是其实很多都是用得
比较少的。
比如提供了cbegincend方法返回const迭代器等等,但是实际意义不大,因为beginend也是
可以返回const迭代器的,这些都是属于锦上添花的操作。
实际上C++11更新后,容器中增加的新方法最后用的插入接口函数的右值引用版本:

http://www.cplusplus.com/reference/vector/vector/emplace_back/

http://www.cplusplus.com/reference/vector/vector/push_back/

http://www.cplusplus.com/reference/map/map/insert/

http://www.cplusplus.com/reference/map/map/emplace/

右值引用和移动语义

左值引用和右值引用
传统的C++语法中就有引用的语法,而C++11中新增了的右值引用语法特性,所以从现在开始我们
之前学习的引用就叫做左值引用。无论左值引用还是右值引用,都是给对象取别名
什么是左值?什么是左值引用?
左值是一个表示数据的表达式(如变量名或解引用的指针)我们可以获取它的地址+可以对它赋
值,左值可以出现赋值符号的左边,右值不能出现在赋值符号左边。定义时const修饰符后的左
值,不能给他赋值,但是可以取它的地址。左值引用就是给左值的引用,给左值取别名。

什么是右值?什么是右值引用?
右值也是一个表示数据的表达式,如:字面常量、表达式返回值,函数返回值(这个不能是左值引 用返回)等等,右值可以出现在赋值符号的右边,但是不能出现出现在赋值符号的左边,右值不能取地址。右值引用就是对右值的引用,给右值取别名。

需要注意的是右值是不能取地址的,但是给右值取别名后,会导致右值被存储到特定位置,且可
以取到该位置的地址,也就是说例如:不能取字面量10的地址,但是rr1引用后,可以对rr1取地
址,也可以修改rr1。如果不想rr1被修改,可以用const int&& rr1去引用。

我的总结:

左值:可以取地址的

右值:不可以取地址的,分为内置类型字面常量,匿名对象/变量,临时对象/变量

左值和右值都存在地址,只是左值能取地址,而右值不能取地址

右值分为纯右值(字面常量)和将亡值(匿名对象/变量,临时对象/变量)

个人猜测:右值引用引用字面常量时,会生成临时变量/对象

int&& p=10;// int b=10; int&& p= b;  b是临时变量

class A
{
public:
    A(int a1, int a2)
        :_a1(a1)
        , _a2(a2)
    {}

private:
    int _a1;
    int _a2;
};

A&& p = { 1,2 };// A b(1,2); A&& p= b; b是临时对象

左值引用与右值引用比较

左值引用总结:
1.左值引用只能引用左值,不能引用右值。
2.但是const左值引用既可引用左值,也可引用右值
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/23 13:50:53

什么是EEAT原则及在ai搜索geo优化中的策略

作者: 白磊 版本号: 1.0 发布日期: 2025年10月 适用场景: AI 搜索培训|SEO 教学|品牌内容策略 版权声明: 本手册来源GEO百科网,仅供学习交流,未经授权请勿商业转载或修改。 🏠 前言 E-E-A-T(经验、专业性、权威性、可信度)是 Google 在人工智能搜索时代中衡量内容…

作者头像 李华
网站建设 2026/8/23 13:49:51

ComfyUI WanVideoWrapper 安装指南:3 步跑通 WanVideo 视频生成

ComfyUI WanVideoWrapper 安装指南&#xff1a;3 步跑通 WanVideo 视频生成 【免费下载链接】ComfyUI-WanVideoWrapper 项目地址: https://gitcode.com/GitHub_Trending/co/ComfyUI-WanVideoWrapper ComfyUI-WanVideoWrapper 是一个 ComfyUI 插件&#xff0c;它把 WanV…

作者头像 李华
网站建设 2026/8/23 13:41:28

告别手打括号:Neovim 自动括号插件 Nvim-Autopairs 上手

告别手打括号&#xff1a;Neovim 自动括号插件 Nvim-Autopairs 上手 【免费下载链接】nvim-autopairs autopairs for neovim written in lua 项目地址: https://gitcode.com/gh_mirrors/nv/nvim-autopairs 写代码时&#xff0c;你打过多少次错位的括号&#xff0c;又回头…

作者头像 李华