当前位置: 首页 > news >正文

【C++11】入门基础

文章目录

  • 1. C++11 简介
  • 2. 统一的列表初始化
    • 2.1{ }初始化
    • 2.2 std::initializer_list
  • 3. 声明
    • 3.1 auto
    • 3.2 decltype
    • 3.3 nullptr
  • 4. 范围 for 循环
  • 5. 智能指针
    • 5.1 unique_ptr
    • 5.2 shared_ptr
    • 5.3 weak_ptr
    • 5.4 总结
  • 6. STL 中一些变化

1. C++11 简介

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

C++11 增加的语法特性非常篇幅非常多,主要讲解实际中比较实用的语法,详情可见官网:C++11 官网。

这里可以科普一个小故事:

1998 年是 C++ 标准委员会成立的第一年,本来计划以后每 5 年视实际需要更新一次标准,C++ 国际标准委员会在研究 C++ 03 的下一个版本的时候,一开始计划是 2007 年发布,所以最初这个标准叫 C++ 07。

但是到 06 年的时候,官方觉得 2007 年肯定完不成 C++ 07,而且官方觉得 2008 年可能也完不成。最后干脆叫 C++ 0x。x 的意思是不知道到底能在07还是08还是09年完成。

结果 2010 年的时候也没完成,最后在 2011 年终于完成了 C++ 标准。所以最终定名为 C++11。

2. 统一的列表初始化

2.1{ }初始化

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

structPoint{int_x;int_y;};intmain(){intarr1[]={1,2,3,4,5};intarr2[5]={0};Point p={1,2};cout<<"arr1: ";for(inti=0;i<sizeof(arr1)/sizeof(arr1[0]);i++){cout<<arr1[i]<<" ";}cout<<endl;cout<<"arr2: ";for(inti=0;i<sizeof(arr2)/sizeof(arr2[0]);i++){cout<<arr2[i]<<" ";}cout<<endl;cout<<"Point: "<<p._x<<" "<<p._y<<endl;return0;}

结果如下:

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

structPoint{int_x;int_y;};intmain(){intx1=1;// 可添加等号intx2{2};// 可不添加等号cout<<x1<<" "<<x2<<endl;intarr1[]{1,2,3,4,5};intarr2[5]{0};Point p{1,2};cout<<p._x<<" "<<p._y<<endl;// C++11中列表初始化也可以用于new表达式中(C++98无法初始化)int*p1=newint[4]{0};int*p2=newint[5]{1,2,3,4,5};return0;}

结果如下:

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

classDate{public://Date(intyear,intmonth,intday):_y(year),_m(month),_d(day){}//~Date(){}private:int_y;// 年int_m;// 月int_d;// 日};intmain(){Dated1(2025,10,1);// 老的初始化方式// C++11支持的列表初始化,这里会调用构造函数初始化Date d2{2025,10,2};Date d3={2025,10,3};return0;}

2.2 std::initializer_list

initializer_list叫做 初始化成员列表,此类型用于访问 C++ 初始化列表中的值,该列表是 const T 类型的元素列表。

std::initializer_list是什么类型呢?

intmain(){// the type of il is an initializer_listautoil={10,20,30};cout<<typeid(il).name()<<endl;return0;}

结果如下:会打印出initializer_list<int>的类型编码,它确实是std::initializer_list<int>,而不是数组,也不是 vector。

注意:它不是一个容器,而是一个 轻量级的只读视图(view),用于支持花括号{ }初始化语法。

它的成员函数如下:

std::initializer_list的使用场景:

  • 一般是作为构造函数的参数,C++11 对 STL 中的不少容器就增加std::initializer_list作为参数的构造函数,这样初始化容器对象就更方便了。也可以作为operator=的参数,这样就可以用大括号赋值。

代码示例:

intmain(){vector<int>v={1,2,3,4};list<int>lt={1,2};// 这里{"sort", "排序"}会先初始化构造一个pair对象map<string,string>dict={{"sort","排序"},{"insert","插入"}};// 使用大括号对容器赋值v={10,20,30};return0;}

1️⃣ 让类支持花括号初始化

我们可以手动模拟实现一个 vector,并让它支持{ }初始化。

// 注意包含头文件#include<initializer_list>classMyVector{public:MyVector(initializer_list<int>list){for(intv:list)_data.push_back(v);}voidprint(){for(intv:_data)cout<<v<<" ";cout<<"\n";}private:vector<int>_data;};intmain(){MyVector v={1,2,3,4};v.print();// 1 2 3 4return0;}

结果如下:

2️⃣ 可作为函数参数

voidfunc(std::initializer_list<int>list){for(autox:list)cout<<x<<" ";cout<<endl;}intmain(){func({10,20,30});return0;}

结果如下:

3. 声明

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

3.1 auto

在 C++98 中 auto 是一个存储类型的说明符,表明变量是局部自动存储类型,但是局部域中定义局部的变量默认就是自动存储类型,所以 auto 就没什么价值了。

C++11 中废弃 auto 原来的用法,将其用于实现自动类型推断。这样要求必须进行显示初始化,让编译器将定义对象的类型设置为初始化值的类型。

代码示例

// 注意头文件#include<typeinfo>#include<cstring>intmain(){inti=10;autop=&i;autopf=strcpy;//strcpy 是 C 标准库函数cout<<typeid(p).name()<<endl;cout<<typeid(pf).name()<<endl;map<string,string>dict={{"sort","排序"},{"insert","插入"}};// map<string, string>::iterator it = dict.begin();autoit=dict.begin();return0;}

结果如下:P表示 pointer,i表示 int

使用 auto 带来好处:

  • 避免冗长的模板声明
  • 自动适应容器变化(比如从 map 换成 unordered_map)
  • 更安全(避免写错类型)

3.2 decltype

关键字 decltype 将变量的类型声明为表达式指定的类型。

// decltype的一些使用使用场景template<classT1,classT2>voidF(T1 t1,T2 t2){decltype(t1*t2)ret;// 对于 F(1,'a'),这里是 intcout<<"F ret: "<<typeid(ret).name()<<endl;}intmain(){constintx=1;doubley=2.2;decltype(x*y)ret;// doubledecltype(&x)p;// const int*cout<<"ret: "<<typeid(ret).name()<<endl;cout<<"p: "<<typeid(p).name()<<endl;F(1,'a');// 打印 intreturn0;}

结果如下:在 GCC/Clang 编译器下 PKi(P=pointer,K=const,i=int)

注意:decltype(x) 与 decltype((x)) 不同!

  • decltype(x):如果 x 声明为 const int,结果是 const int。
  • decltype((x)):(x) 是左值表达式 → 结果是 const int&。

3.3 nullptr

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

因为 NULL 在 C++ 中通常是:

#defineNULL0// 或者 (void*)0,但 C++ 中通常是 0

而 0 可以:

  • 作为整型字面量
  • 作为空指针常量

导致一些二义性和重载歧义问题,使用 NULL 可能出现麻烦:

voidf(int);voidf(char*);f(NULL);// 调用哪个??

因为:NULL == 0,优先匹配 int,调用 f(int),但期望可能是 f(char*)

4. 范围 for 循环

范围 for 循环(Range-based for loop) 是 C++11 引入的一种简化遍历容器的语法,让你像 Python/Java 一样优雅地遍历序列。

例子:

intmain(){vector<int>v={1,2,3};for(intx:v){cout<<x<<" ";}cout<<endl;return0;}

结果如下:

这里注意一下:引用 vs 非引用

❌ 拷贝遍历(默认)

for(intx:v)x=100;// 不会修改 v

✅ 引用遍历(允许修改原容器)

for(int&x:v)x=100;// ✅ 修改原容器

✅ const 引用(避免拷贝、只读)

for(constint&x:v){cout<<x<<"\n";}

所以,推荐使用for (const auto& x : container)

例子:

intmain(){map<string,int>m={{"A",1},{"B",2}};// 第一种for(constauto&p:m){cout<<p.first<<":"<<p.second<<"\n";}return0;}

结果如下:

它的底层展开机制是,编译器会转为类似如下:

for(autox:range)👇for(autoit=begin(range);it!=end(range);++it){autox=*it;}

所以,不建议对容器 while 遍历中修改结构(如 erase)

5. 智能指针

智能指针(Smart Pointer)是 C++11 引入的 RAII(资源获取即初始化)机制 用来自动管理动态内存,避免手动 delete 导致的内存泄漏与悬空指针问题。

核心思想:对象生命周期绑定在智能指针上,离开作用域自动 delete。

C++ 常见智能指针:

智能指针所在头文件所有权语义使用场景
unique_ptr<memory>独占所有权(唯一所有者)资源严格只能被一个对象拥有
shared_ptr<memory>共享所有权(引用计数)多个对象共享同一资源
weak_ptr<memory>弱引用(不影响引用计数)解决 shared_ptr 循环引用

5.1 unique_ptr

独占所有权

#include<iostream>#include<memory>usingnamespacestd;intmain(){unique_ptr<int>p1(newint(10));cout<<*p1<<endl;// unique_ptr 禁止拷贝,只能移动unique_ptr<int>p2=move(p1);return0;}

结果如下:

5.2 shared_ptr

引用计数

#include<iostream>#include<memory>usingnamespacestd;intmain(){autop1=make_shared<int>(20);autop2=p1;// 引用计数 +1cout<<p1.use_count()<<endl;// 2return0;}

结果如下:

5.3 weak_ptr

防止循环引用

shared_ptr<A>a=make_shared<A>();shared_ptr<B>b=make_shared<B>();a->b=b;b->a=a;// ❌ 循环引用 = 内存泄漏

使用 weak_ptr 解决

classB;classA{public:weak_ptr<B>b;// 不增加引用计数};

上面代码的循环引用示例图:

shared_ptr shared_ptr A<---------------->B^^||+-----weak_ptr-----+

5.4 总结

智能指针最佳实践总结:

  • 优先使用std::unique_ptr
  • 多所有权才用std::shared_ptr
  • 有关联对象互相引用时使用std::weak_ptr
  • 用 make_unique/make_shared 创建对象
  • 避免 new/delete 出现在业务逻辑

6. STL 中一些变化

圈起来是 C++11 中的一些几个新容器,但是实际最有用的是 unordered_map 和 unordered_set。

容器中的一些新方法:

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

需要详细了解容器的新特性,可以访问 STL容器,具体会在【右值引用】和【移动语义】章节重点说明。

http://www.jsqmd.com/news/502042/

相关文章:

  • 揭秘Gifski拖放区域设计:UI交互背后的文件类型检测逻辑
  • Robo 3T主题定制完全指南:10款高颜值界面配置方案分享
  • 如何使用waifu2x-caffe:AI驱动的图像放大与降噪完整指南
  • 研究生必备!2026年最全文献阅读工具对比:告别翻译软件,这样读外文文献效率翻10倍
  • 学长亲荐!AI论文软件 千笔写作工具 VS 灵感ai,开源免费首选
  • @Transactional 事务失效的几种情况解析
  • 大模型进阶必看:Skill机制深度解析,比Prompt好用,程序员建议收藏
  • 如何参与FastSAM开源项目贡献:从发现问题到提交PR的完整指南
  • 终极指南:waifu2x-caffe图像放大中断恢复全攻略,让处理不重来
  • 如何高效管理Boot2Docker磁盘空间:掌握boot2docker-data标签的ext4分区技巧
  • PHP 给定 n 个有序顶点的多边形的面积(Area of a polygon with given n ordered vertices)
  • 深度学习注意力可视化终极指南:如何理解模型决策过程与注意力机制
  • 终极指南:如何用sh1/sh实现安全的日志聚合与数据保护
  • Nuclide分支命名工具集成:Git钩子配置终极指南
  • 终极Android自定义View绘制指南:掌握onDraw与Canvas的完整流程
  • JavaScript 给定 n 个有序顶点的多边形的面积(Area of a polygon with given n ordered vertices)
  • 金融风控实战指南:使用auto-sklearn快速构建欺诈检测模型
  • 如何加入twin.macro社区:探索贡献与成长机会
  • 7个关键策略:MCP应用容器编排与备份最佳实践指南
  • 终极macOS启动盘制作指南:使用开源工具轻松创建系统安装盘
  • 电池组散热性能分析:基于ANSYS Fluent流体动力学模拟的研究
  • 7个关键步骤:FastSAM模型生产环境监控与告警实践指南
  • Gifski无障碍支持:为视障用户优化的视频转GIF工具详解
  • 5款免费开源电池管理工具:延长MacBook续航的终极指南
  • 终极指南:oapi-codegen生成代码的容器化与Serverless部署策略对比
  • 终极Android开发指南:掌握Dagger Hilt依赖注入的核心技巧
  • 2024-2026年北京房产继承律师推荐:涉及拆迁补偿的继承纠纷处理热门律师深度剖析 - 品牌推荐
  • SQLGlot深度学习集成指南:如何用AI处理图像与文本数据的SQL查询
  • 2026年北京继承律所推荐:遗嘱执行与财产分割高性价比服务及避坑指南 - 品牌推荐
  • 如何在Robo 3T中配置MongoDB Atlas文本搜索索引:完整指南