【C++进阶篇】C++11新特性(上篇)

article/2025/7/7 0:23:04

💡 解锁C++11新技能:初始化、类型推导与智能指针的奥秘!

  • 一. C++11简介
    • 1.1 C++11发展历史
  • 二. 初始化列表
    • 2.1 内置类型
    • 2.2 initializer_list详解
  • 三. 简化声明
    • 3.1 auto 自动推导类型
      • 3.2.1 注意事项
    • 3.3 decltype 获取推导类型
      • 3.3.1 没有括号
      • 3.3.2 有括号
      • 3.3.3 左值
      • 3.3.4 右值
  • 四. 智能指针
    • 4.1 RAII
    • 4.2 分类
  • 五. 最后

一. C++11简介

1.1 C++11发展历史

C++11的前身是C++0x,其标准化历程跨越近十年:

  • 2003年:C++03发布(小修小补版本),ISO委员会启动C++0x项目,原计划200X年完成。
  • 2005年:提出“Concepts”(概念)特性,但因复杂度被推迟至C++20
  • 2007年:草案初稿完成,因特性过多首次延期。
  • 2010年:特性冻结,提交最终委员会草案(FDIS)。
  • 2011年8月12日:ISO正式批准为ISO/IEC 14882:2011,同年9月标准发布,终结了C++98/03时代。

实践:C++每隔3年更新一次

二. 初始化列表

列表初始化 { } 几乎适用于任意数据类型,成为现代编码的推荐方式。合理利用其特性可以可显著提升可读性和健壮性。

2.1 内置类型

C++内置类型几乎都具有一个默认的构造函数。行为:对值进行拷贝。

#include<iostream>
using namespace std;int main()
{//内置类型的构造函数int a(10);char x('c');cout << a << " " << x << endl;return 0;
}

在这里插入图片描述
C++11扩大了{}的范围,对任意类型数据都可以使用其进行初始化。

#include<iostream>
using namespace std;int main()
{//内置类型的构造函数int a{ 10 };int arr[]{ 1,2,3,4,5 };cout << a << " " << arr[0] << endl;return 0;
}

在这里插入图片描述
本质:使用初始化列表{}构造一个临时对象,再用该临时对象拷贝构造,被编译器优化成直接构造。
如何验证呢???思路:就是使用某种关键字,该关键字具有防止隐式类型转换的功能。

下面写出一个简单Date类

在这里插入图片描述
从结果中可以看出没有什么问题,下面我们将构造函数用 explicit 修饰。

  • explicit 关键字用于修饰构造函数,它的主要作用是:
  1. 防止编译器进行隐式类型转换。
  2. 当构造函数被标记为explicit时,这个构造函数就只能被显式地调用,而不能被编译器用于隐式类型转换。
  • 如下图:

在这里插入图片描述

  • 本质:
  1. 使用复制列表初始化 (Date d1 = { 2023, 11,8 }😉 时,由于这种方式可能涉及隐式转换(创建临时对象),而构造函数是explicit的,所以编译器阻止了这种隐式转换,导致初始化失败。
  2. 直接列表初始化 (Date d2{ 2023, 11,8 }😉 是直接调用构造函数,不涉及隐式转换,因此即使构造函数是explicit的,初始化仍然可以成功。

2.2 initializer_list详解

int main()
{auto arr = { 1,2,3,4,5 };cout << typeid(arr).name() << endl;return 0;
}

在这里插入图片描述

  • 注意:并不是使用{}就是 initializer_list -> 看下图:

在这里插入图片描述
该类具有size(),begin(),end(),用于遍历该类中的数据。同时该类具有迭代器,所以支持范围for遍历。值得注意的是:C++库中vector,list,map都具有initializer_list该类的构造。

  • 更简洁的写法:

int main()
{pair<string,string> kv1(make_pair("sort", "排序"));//传统写法unordered_map<string, string> dict{{ "banana","香蕉" }, { "insert","插入" }, { "orange","橙子" }};dict.insert(kv1);dict.insert({ "right","右边" });//现代写法return 0;
}

可以看出再插入时前面代码较多,后面的代码简洁且易懂。

三. 简化声明

对于一个数据类型可能它的类型非常长,在上篇红黑树封装就使用过,如下:
在这里插入图片描述

3.1 auto 自动推导类型

auto一般适用于对于复杂类型,类型很长,或不关心,就可以考虑使用auto,大大简化代码的复杂化。

int main()
{unordered_map<string, string> dict{ { "banana","香蕉" }};//都是哈希表的初始迭代器,只是用不同的变量存储unordered_map<string, string>::iterator it = dict.begin();auto it1 = dict.begin();cout << typeid(it).name() << endl;cout << typeid(it1).name() << endl;return 0;
}
  • 输出结果:

在这里插入图片描述

3.2.1 注意事项

  1. 类型推导规则:auto类型推导会忽略顶层const和引用语义。
int x = 10;
auto a = x; // a的类型被推导为intconst int& ref = x;
auto b = ref; // b的类型被推导为int(顶层const和引用被忽略)
  1. 必须初始化:使用auto声明的变量必须进行初始化,否则编译器无法推导其类型,会导致编译错误。
auto c; // 错误:未初始化的auto变量
  1. 指针和引用:当使用auto声明指针或引用时,需要显式指定指针或引用符号。
int x = 10;
int* ptr = &x;//auto ptrAuto = ptr;
auto* ptrAuto = ptr; // ptrAuto的类型是int*(指针)
auto& refAuto = x;  // refAuto的类型是int&(引用)
  1. 函数返回值:在C++14及以后的标准中,auto可以用于函数返回类型,此时函数的返回类型由return语句推导得出。
auto add(int a, int b) {return a + b; // 返回类型被推导为int
}

3.3 decltype 获取推导类型

decltype 是一个类型推导关键字,它用于查询表达式的类型。
语法如下:

decltype(expression)
其中 expression 是任意一个合法的 C++ 表达式。decltype 会分析这个表达式,并推导出其类型。

3.3.1 没有括号

如果 expression 是一个没有用括号括起来的标识符(比如变量名、函数名、类名等)或者一个类成员访问表达式(比如 obj.member 或 ptr->member),那么 decltype(expression) 的类型就是该表达式结果的类型。

int x = 0;
decltype(x) y = 10; // y 的类型是 intstruct MyStruct { int a; };
MyStruct s;
decltype(s.a) z = 20; // z 的类型是 int

3.3.2 有括号

如果 expression 是一个用括号括起来的标识符(比如 (x)),那么 decltype(expression) 的类型是该标识符的类型的左值引用(即 T&,其中 T 是标识符的类型)。

int x = 0;
decltype((x)) ref = x; // ref 的类型是 int&
ref = 20; // 修改 ref 也会修改 x

3.3.3 左值

如果 expression 是一个左值(可以出现在赋值语句左边的表达式),那么 decltype(expression) 的类型是该表达式类型的左值引用(即 T&)。

int arr[5] = {0};
decltype(arr[0]) elem_ref = arr[0]; // elem_ref 的类型是 int&int& ref_x = x;
decltype(ref_x) another_ref = x; // another_ref 的类型是 int&

3.3.4 右值

如果 expression 是一个右值(比如字面量、临时对象、函数调用返回的非引用类型等),那么 decltype(expression) 的类型就是该表达式结果的类型。

int func() { return 0; }
decltype(func()) val = 10; // val 的类型是 intdecltype(10) another_val = 20; // another_val 的类型是 int

四. 智能指针

4.1 RAII

RAII是C++中一种重要的资源管理技术,全称为Resource Acquisition Is Initialization,即资源获取即初始化。它是一种利用对象的生命周期来自动管理资源的技术,能够有效地防止资源泄漏,提高代码的健壮性和可维护性。

  • RAII的核心思想是将资源的生命周期与对象的生命周期紧密绑定。具体来说,它遵循以下两个原则:
  1. 资源获取即初始化(Resource Acquisition Is Initialization):在对象的构造函数中完成资源的获取(分配)。这意味着,当对象被创建时,它所管理的资源也被同时获取。
  2. 资源释放即析构(Resource Release Is Destruction):在对象的析构函数中完成资源的释放(清理)。这意味着,当对象生命周期结束,被销毁时,它所管理的资源也会被自动释放。

简单点说:就是利用C++的特性,一个对象被创建自动调用构造函数,该对象生命周期时,自动周期结束自动调用析构函数,清理和释放资源。

4.2 分类

C++11 的智能指针有 u n i q u e p t r \color{Red}unique_ptr uniqueptr a u t o p t r \color{Red}auto_ptr autoptr s h a r e d p t r \color{Red}shared_ptr sharedptr w e a k p t r \color{Red}weak_ptr weakptr是专门用来解决 s h a r e d p t r \color{Red}shared_ptr sharedptr存在循环引用,导致内存泄漏的方案。 u n i q u e p t r \color{Red}unique_ptr uniqueptr a u t o p t r \color{Red}auto_ptr autoptr这两个智能指针区别在于是否支持拷贝。
推荐使用: s h a r e d p t r \color{Red}shared_ptr sharedptr,如果某种场景不需要拷贝,推荐使用 u n i q u e p t r \color{Red}unique_ptr uniqueptr,最不推荐使用: a u t o p t r \color{Red}auto_ptr autoptr
详细细节见下篇文章。
下面来展示一个简单例子来看一下过程,示例代码如下:

#include<memory>
class A
{
public:A(){cout << "A()" << endl;}~A(){cout << "~A()" << endl;}
};
int main()
{shared_ptr<A> a(new A);return 0;
}

输出结果:
在这里插入图片描述
可以看到析构函数被调用了,资源被正确的清理。

五. 最后

本文深入探讨了C++11的关键特性,涵盖其发展历程、列表初始化、类型推导简化及智能指针等核心主题。C++11作为C++语言的重大更新,引入了诸多改进,显著提升了代码的可读性、安全性和开发效率。列表初始化通过统一的{}语法,增强了类型安全和代码一致性。auto和decltype关键字则简化了复杂的类型声明,使代码更加简洁易读。此外,智能指针和RAII技术的引入,有效解决了资源管理难题,防止了内存泄漏,提高了程序的健壮性。总体而言,C++11的这些特性共同推动了C++语言的现代化进程,使其更加适应现代软件开发的需求。


http://www.hkcw.cn/article/dnYDQQhZBu.shtml

相关文章

Unity中应对高速运动的物体,碰撞组件失效的问题?

尝试方法一:修改重力组件Rigidbody中的碰撞检测模式Collision Detection 把碰撞检测模式Collision Detection属性修改成Continuous Dynamic后,发现效果不是很明显,还会有碰撞组件失效的问题。 尝试方法二:射线检测替代物理碰撞 private Vector3 _prevPos;void Start() {…

高性能MYSQL(三):性能剖析

一、性能剖析概述 &#xff08;一&#xff09;关于性能优化 1.什么是性能&#xff1f; 我们将性能定义为完成某件任务所需要的时间度量&#xff0c;换句话说&#xff0c;性能即响应时间&#xff0c;这是一个非常重要的原则。 我们通过任务和时间而不是资源来测量性能。数据…

《深入解析SPI协议及其FPGA高效实现》-- 第二篇:SPI控制器FPGA架构设计

第二篇&#xff1a;SPI控制器FPGA架构设计 聚焦模块化设计、时序优化与资源管理 1. 系统级架构设计 1.1 模块化硬件架构 verilog module spi_controller (input wire clk, // 系统时钟 (100 MHz)input wire rst_n, // 异步复位// 配置接口…

rabbitmq Fanout交换机简介

给每个服务创建一个队列&#xff0c;然后每个业务订阅一个队列&#xff0c;进行消费。 如订单服务起个多个服务&#xff0c;代码是一样的&#xff0c;消费的也是同一个队列。加快了队列中的消息的消费速度。 可以看到两个消费者已经在消费了

Ⅱ.计算机二级选择题(运算符与表达式)

【注&#xff1a;重点题以及添加目录格式导航&#xff01;&#xff01;&#xff01;】 【重点题】&#xff08;第5题&#xff09; 【重点题】&#xff08;第18题&#xff09; 【重点题】&#xff08;第19题&#xff09; 【重点题】&#xff08;第35题&#xff09; 【重点题】&a…

使用Mathematica观察多形式根的分布随参数的变化

有两种方式观察多项式的根随着参数变化&#xff1a;&#xff08;1&#xff09;直接制作一个小的动态视频&#xff1b;&#xff08;2&#xff09;绘制所有根形成的痕迹&#xff08;locus&#xff09;。 制作动态视频&#xff1a; (*Arg-plane plotting routine with plotting …

腾答知识竞赛系统功能介绍

支持抢答题的局域网现场大屏知识竞赛抢答软件&#xff0c;无需网络只要有局域网或者WIFI就可以使用,现场大屏幕显示题目&#xff0c;支持基础题、抢答题、必答题、风险题等题目。 系统支持任何个人或者企业单位使用&#xff0c;使用无人员限制&#xff0c;可放心使用。 抢答时…

Python-matplotlib库之核心对象

matplotlib库之核心对象 FigureFigure作用Figure常用属性Figure常用方法Figure对象的创建隐式创建&#xff08;通过 pyplot&#xff09;显式创建使用subplots()一次性创建 Figure 和 Axes Axes&#xff08;绘图区&#xff09;Axes创建方式Axes基本绘图功能Axes绘图的常用参数Ax…

04powerbi-度量值-筛选引擎CALCULATE()

1、calculate calculate 的参数分两部分&#xff0c;分别是计算器和筛选器 2、多条件calculater与表筛选 多条件有不列的多条件 相同列的多条件 3、calculatertable &#xff08;表&#xff0c;筛选条件&#xff09;表筛选 与calculate用法一样&#xff0c;可以用创建表&…

深度学习原理与Pytorch实战

深度学习原理与Pytorch实战 第2版 强化学习人工智能神经网络书籍 python动手学深度学习框架书 TransformerBERT图神经网络&#xff1a; 技术讲解 编辑推荐 1.基于PyTorch新版本&#xff0c;涵盖深度学习基础知识和前沿技术&#xff0c;由浅入深&#xff0c;通俗易懂&#xf…

LabelImg: 开源图像标注工具指南

LabelImg: 开源图像标注工具指南 1. 简介 LabelImg 是一个图形化的图像标注工具&#xff0c;使用 Python 和 Qt 开发。它是目标检测任务中最常用的标注工具之一&#xff0c;支持 PASCAL VOC 和 YOLO 格式的标注输出。该工具开源、免费&#xff0c;并且跨平台支持 Windows、Lin…

React---day6、7

6、组件之间进行数据传递 **6.1 父传子&#xff1a;**props传递属性 父组件&#xff1a; <div><ChildCpn name"蒋乙菥" age"18" height"1,88" /> </div>子组件&#xff1a; export class ChildCpn extends React.Component…

LLM模型量化从入门到精通:Shrink, Speed, Repeat

前言 神经网络把它们的知识都存成数字啦&#xff0c;主要是训练时学到的权重&#xff0c;还有运行时在每一层流动的激活值。这些数字必须保持在一个固定的数值格式里&#xff0c;而选的格式就决定了每个参数要占多少内存。要是用默认的32位浮点表示&#xff0c;一个有70亿参数…

PHP舆情监控分析系统(9个平台)

PHP舆情监控分析系统&#xff08;9个平台&#xff09; 项目简介 基于多平台热点API接口的PHP实时舆情监控分析系统&#xff0c;无需数据库&#xff0c;直接调用API实时获取各大平台热点新闻&#xff0c;支持数据采集、搜索和可视化展示。 功能特性 &#x1f504; 实时监控 …

贪心算法应用:多重背包启发式问题详解

贪心算法应用&#xff1a;多重背包启发式问题详解 多重背包问题是经典的组合优化问题&#xff0c;也是贪心算法的重要应用场景。本文将全面深入地探讨Java中如何利用贪心算法解决多重背包问题。 多重背包问题定义 **多重背包问题(Multiple Knapsack Problem)**是背包问题的变…

AI预测3D新模型百十个定位预测+胆码预测+去和尾2025年6月2日第96弹

从今天开始&#xff0c;咱们还是暂时基于旧的模型进行预测&#xff0c;好了&#xff0c;废话不多说&#xff0c;按照老办法&#xff0c;重点8-9码定位&#xff0c;配合三胆下1或下2&#xff0c;杀1-2个和尾&#xff0c;再杀4-5个和值&#xff0c;可以做到100-300注左右。 (1)定…

布隆过滤器

文章目录 布隆过滤器&#xff08;Bloom Filter&#xff09;详解&#xff1a;原理、实现与应用场景一、引言二、布隆过滤器的基本原理1. 数据结构2. 插入操作3. 查询操作4. 误判率 三、布隆过滤器的实现四、布隆过滤器的应用场景1. 网络爬虫2. 缓存穿透防护3. 垃圾邮件过滤4. 分…

给stm32cubeide编译出来的bin文件追加crc32

在工程目录下创建ci目录&#xff0c;将AddCrc32.exe丢进去&#xff0c;在stm32cubeide的properties----C/C Build----Settings----Build Steps----Post-build steps Command:添加AddCrc32.exe的路径: source code如下&#xff1a; #include <stdio.h> #include <stdl…

算法-集合的使用

1、set常用操作 set<int> q; //以int型为例 默认按键值升序 set<int,greater<int>> p; //降序排列 int x; q.insert(x); //将x插入q中 q.erase(x); //删除q中的x元素,返回0或1,0表示set中不存在x q.clear(); //清空q q.empty(); //判断q是否为空&a…

网络地址转换

网络地址转换 网络地址转换(Network Address Translation&#xff0c;NAT)的功能是将企业内部自行定义的私有IP地址转换为Internet上可识别的合法IP地址。由于现行IP地址标准--IPv4的限制&#xff0c;Internet面临着IP地址空间短缺的问题&#xff0c;因此从ISP申请并给企业的每…