从C++“新兵”到“老兵”,C++2.0特性全解析!

目录

一、C++2.0:C++ 的华丽蜕变

二、语法糖的甜蜜升级

2.1 auto:类型推断的魔法棒

2.2 原始字面量:字符串表达的新姿势

三、迭代与循环的革新

3.1 基于范围的 for 循环:遍历的优雅之选

3.2 范围库(Ranges):迭代器的华丽变身

四、初始化的新玩法

4.1 列表初始化:大括号的神奇力量

4.2 指定初始化:精准初始化的新方式

五、模板与泛型的进化

5.1 Concepts:模板的类型约束神器

5.2 Variadic Templates:参数数量可变的模板

六、智能指针与资源管理

6.1 智能指针:自动管理内存的利器

6.2 资源管理的最佳实践

七、并发编程的新支持

7.1 协程:轻量级线程的崛起

7.2 并发库的增强

八、总结与展望


一、C++2.0:C++ 的华丽蜕变

        在编程语言的璀璨星空中,C++ 无疑是一颗耀眼的巨星。自 1985 年诞生以来,C++ 凭借其高效性、灵活性以及对硬件的直接操控能力,在系统开发、游戏编程、嵌入式系统等众多领域占据着举足轻重的地位 。从操作系统的底层代码到 3A 游戏的精美画面渲染,从高性能的服务器端程序到资源受限的嵌入式设备,C++ 的身影无处不在,它以强大的表现力和卓越的性能,满足了各种复杂场景的开发需求,成为了无数开发者手中的得力工具。

        随着技术的飞速发展和编程需求的日益增长,C++ 也在不断进化。C++2.0 版本(通常指 C++20 及后续版本,这里统一以 C++2.0 来强调其重大更新特性)的到来,就像是一场华丽的蜕变,为这门古老而强大的编程语言注入了全新的活力,带来了一系列令人瞩目的新特性和改进,再次吸引了全球开发者的目光。 这些新特性不仅解决了以往版本中存在的一些痛点和难题,还为开发者提供了更强大的编程能力和更高效的开发方式,使 C++ 能够更好地适应现代软件开发的挑战,继续在编程语言的舞台上绽放光彩。那么,C++2.0 究竟有哪些神奇的变化呢?让我们一同揭开它神秘的面纱。

二、语法糖的甜蜜升级

        在 C++ 的编程世界里,语法糖就像是一把神奇的钥匙,能够让代码更加简洁、优雅,提升开发效率。C++2.0 带来了一系列语法糖的升级,为开发者们带来了更加甜蜜的编程体验。

2.1 auto:类型推断的魔法棒

        在 C++2.0 中,auto关键字变得更加智能和强大,它就像是一根魔法棒,能够让编译器自动推断变量的类型 。在以往的 C++ 编程中,当我们声明一个变量时,需要明确指定其类型,例如int num = 10; ,这里我们清楚地声明了num是一个整型变量。但在一些复杂的场景中,变量的类型可能很难一眼看出或者书写起来非常繁琐。比如,当使用标准库中的容器和迭代器时,像std::vector<int>::iterator it = vec.begin(); ,这里std::vector<int>::iterator的类型声明冗长又复杂,不仅容易出错,还会影响代码的可读性。

        而有了auto关键字,这一切变得简单多了。我们可以直接写成auto it = vec.begin(); ,编译器会根据vec.begin()的返回类型自动推断出it的类型是std::vector<int>::iterator。这样,我们就无需手动书写复杂的类型声明,代码也变得更加简洁明了。

        auto关键字在模板编程中也发挥着巨大的作用。在模板函数中,变量的类型往往依赖于模板参数,很难预先确定。使用auto关键字,编译器可以根据实际传入的参数类型来推导变量的类型,大大提高了代码的灵活性和通用性。比如:

template<typename T1, typename T2>

auto add(T1 a, T2 b) -> decltype(a + b) {

return a + b;

}

        在这个模板函数中,auto用于返回类型的推导,decltype(a + b)指定了返回类型为a + b的实际类型。这样,无论传入的a和b是什么类型,函数都能正确返回相应类型的结果 。

2.2 原始字面量:字符串表达的新姿势

        在 C++2.0 中,原始字面量为字符串的表达带来了全新的姿势 。在传统的 C++ 中,字符串中的特殊字符需要使用转义字符来表示,例如,要表示一个包含换行符的字符串,需要写成"Hello\nWorld" ,这里的\n表示换行符。如果字符串中包含大量的特殊字符,如反斜杠\、双引号"等,转义字符的使用会使字符串变得难以阅读和维护。

        原始字面量的出现解决了这个问题。原始字面量以R"("开头,以")"结尾,中间的内容不需要转义字符,会被原样输出。例如:

std::string path = R"(C:\Program Files\MyApp\config.txt)";

        在这个例子中,使用原始字面量表示文件路径,无需对反斜杠进行转义,代码更加简洁直观。再比如,当我们需要在代码中嵌入一段 HTML 代码时,原始字面量的优势就更加明显了:

std::string html = R"(

<!DOCTYPE html>

<html lang="zh">

<head>

<meta charset="UTF-8">

<meta name="viewport" content="width=device-width, initial-scale=1.0">

<title>Hello World</title>

</head>

<body>

<h1>Hello World</h1>

</body>

</html>

)";

        使用原始字面量,我们可以直接将 HTML 代码原样嵌入,无需对其中的特殊字符进行繁琐的转义,大大提高了代码的可读性和可维护性。

三、迭代与循环的革新

        在 C++ 编程中,迭代和循环是处理数据集合的常用手段。C++2.0 带来了基于范围的 for 循环和范围库(Ranges),为迭代与循环操作带来了革新,让代码更加简洁、高效。

3.1 基于范围的 for 循环:遍历的优雅之选

        基于范围的 for 循环是 C++11 引入的一个非常实用的特性,在 C++2.0 中进一步得到完善和推广。它的语法简洁明了,让遍历容器和数组变得轻而易举 。传统的 for 循环遍历一个std::vector容器时,需要手动管理迭代器,例如:

#include <iostream>

#include <vector>

int main() {

std::vector<int> vec = {1, 2, 3, 4, 5};

for (std::vector<int>::iterator it = vec.begin(); it != vec.end(); ++it) {

std::cout << *it << " ";

}

std::cout << std::endl;

return 0;

}

        这段代码中,我们需要声明一个迭代器it,并使用begin()和end()函数来确定循环的起始和结束条件,同时还要手动解引用迭代器来获取容器中的元素,代码显得较为繁琐。

        而使用基于范围的 for 循环,代码可以简化为:

#include <iostream>

#include <vector>

int main() {

std::vector<int> vec = {1, 2, 3, 4, 5};

for (auto num : vec) {

std::cout << num << " ";

}

std::cout << std::endl;

return 0;

}

        在这个例子中,auto关键字让编译器自动推断num的类型,for (auto num : vec)表示对vec容器中的每个元素进行迭代,将每个元素依次赋值给num,循环体中可以直接使用num来操作元素,无需关心迭代器的细节,代码更加简洁易读。

        如果需要在遍历过程中修改容器中的元素,可以使用引用类型:

#include <iostream>

#include <vector>

int main() {

std::vector<int> vec = {1, 2, 3, 4, 5};

for (auto& num : vec) {

num *= 2; // 将每个元素乘以2

}

for (auto num : vec) {

std::cout << num << " ";

}

std::cout << std::endl;

return 0;

}

        这里auto& num表示num是容器中元素的引用,对num的修改会直接反映到容器中的元素上。 基于范围的 for 循环不仅适用于标准库容器,还适用于任何支持迭代器的类型,或者定义了begin()和end()方法的类型,具有很强的通用性。

3.2 范围库(Ranges):迭代器的华丽变身

        范围库(Ranges)是 C++20 引入的一个重要特性,它建立在迭代器的基础之上,为数据处理提供了更高层次的抽象,让代码更加简洁、高效和可读 。范围库引入了 “范围”(Range)和 “视图”(View)的概念。范围表示一个可迭代的序列,可以是容器、数组或任何支持范围概念的类型;视图则是一种轻量级、非拥有的数据访问方式,它对数据进行某种形式的转换或过滤,但不复制或拥有底层数据 。

        范围库的一个显著特点是惰性求值(Lazy Evaluation)机制。这意味着对数据的操作只有在实际需要时才执行,而不是立即执行。例如,当我们使用std::views::filter和std::views::transform对一个范围进行链式操作时,这些操作不会立即执行,而是在最终遍历范围时才会依次执行,这样可以避免不必要的计算和内存分配,提高程序的性能 。

        通过下面这个例子,我们可以更好地理解范围库的强大之处。假设我们有一个整数向量vec,现在需要从中筛选出所有偶数,并将这些偶数平方后打印出来。使用传统的迭代器和算法,代码可能如下:

#include <iostream>

#include <vector>

#include <algorithm>

#include <functional>

int main() {

std::vector<int> vec = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

std::vector<int> temp;

std::copy_if(vec.begin(), vec.end(), std::back_inserter(temp), [](int num) {

return num % 2 == 0;

});

std::vector<int> result;

std::transform(temp.begin(), temp.end(), std::back_inserter(result), [](int num) {

return num * num;

});

for (auto num : result) {

std::cout << num << " ";

}

std::cout << std::endl;

return 0;

}

        在这段代码中,我们需要手动创建两个临时容器temp和result,分别用于存储筛选出的偶数和平方后的结果。代码涉及多个函数调用和临时容器的管理,逻辑较为复杂,可读性较差。

        而使用范围库,代码可以简化为:

#include <iostream>

#include <vector>

#include <ranges>

int main() {

std::vector<int> vec 
学习并掌握C++2.0(11+14+17+20)的新特性,学习线程及线程池的应用 ---------------------------------------------------给小白学员的3年学习路径及计划技术方面分三块:1.纯开发技术方向2.音视频流媒体专业方向3.项目实战---------------------------------------------------1.纯开发技术方向(1) C++必须要过硬(至少学会10本经典好书)(2) 系统级编程(Windows、Linux),必须特别熟练系统API,灵活运用(3) 框架与工具(Qt、MFC):必须精通其中一种。(4) 架构与设计模式:需要提升一个高度,不再是简单的编码,而是思维模式。(5) 驱动级别(如果有兴趣,可以深入到驱动级:包括Windows、Linux)(6) 最好学习点Java+Html+javascript等WEB技术。2.音视频流媒体专业方向(1) 音视频流媒体基础理论:   必须认真学会,否则看代码就是看天书(2) 编解码方向:精通h.264,h.265(hevc), 包括理论和各个开源库(ffmpeg,libx264,libx265,...)。(3) 直播方向:  精通各种直播协议(rtsp,rtmp,hls,http-flv,...), 钻研各个开源库(live555,darwin,srs,zlmediakit,crtmpserver,...)(4) 视频监控:  理论+开源库(onvif+281818)(EasyMonitor、iSpy、ZoneMinder(web)、...) 3.项目实战(1) Qt项目:  至少要亲手练习10个实战项目(网络服务器、多线程、数据库、图像处理、多人聊天、等等)(2)音视频项目:包括编解码、视频监控、直播等各个方向,都需要亲手实战项目,包括视频服务器、后台管理系统、前端播放器(多端)---------------------------------------------------  第1章 C++11新特性 41). nullptr关键字与新语法 42). auto和decltype类型推导 6 auto讲解 6 auto示例 7 decltype 83). for区间迭代 94). 初始化列表 105). 模板增强 11外部模板 11类型别名模板 12默认模板参数 126). 构造函数 13委托构造 13继承构造 147). Lambda 表达式 158). 新增容器 20std::array 20std::forward_list 21无序容器 22元组 std::tuple 239). 正则表达式 2610). 语言级线程支持 28多线程库简介 2811). 右值引用和move语义 31右值引用和move语义 32转移左值 3412). constexpr 35第2C++14新特性 36Lambda 函数 36类型推导 37返回值类型推导(Return type deduction) 37泛型lambda 39[[弃用的]]  [[deprecated]]属性 40二进制数字和数字分隔符 41第3章 C++17新特性 42安装GCC10.2 42安装msys2-x86_64-20200720 42更新镜像 42更新软件库 43安装 MinGW64 等必要的软件 43环境变量Path 43编译命令 43constexpr 44typename 45折叠表达式 47结构化绑定 48条件分支语句初始化 49聚合初始化 50嵌套命名空间 52lambda表达式捕获*this的值 53改写/继承构造函数 54用auto作为非类型模板参数 55__has_include 56fallthrough 57nodiscard 57maybe_unused 58第4章 C++20特性 59编译命令 59concept 59typename 60explicit 61constinit 62位域变量的默认成员初始化 62指定初始化 63基于范围的for循环初始化 64放宽基于范围的for循环,新增自定义范围方法 65嵌套内联命名空间 66允许用圆括弧的值进行聚合初始化 67unicode字符串字面量 68允许转换成未知边界的数组 68likely和unlikely 69第5章 C++2.0(11/14/17/20)总结与分析 705.1 C语言与C++ 715.2 语言可用性的强化 725.2.1 常量 725.2.2 变量及其初始化 735.2.3 类型推导 745.2.4 控制流 765.2.5 模板 775.2.6 面向对象 815.3 语言运行期的强化 835.3.1 Lambda 表达式 835.3.2 右值引用 865.4 容器 885.4.1 线性容器 885.4.2 无序容器 895.4.3 元组 895.5 智能指针与内存管理 905.5.1 RAII 与引用计数 905.5.2 std::shared_ptr 905.5.3 std::unique_ptr 915.5.4 std::weak_ptr 91第6章 C++2.0多线程原理与实战 93什么是并发 93并发的方式 93为什么使用并发 95线程简介 96创建线程的三种方式 971. 通过函数 972.通过类对象创建线程 993.通过lambda表达式创建线程 101thread线程的使用 101互斥量与临界区 105期物Future 111条件变量 112原子操作 114内存模型 118第7章 C++2.0线程池原理与实战 120线程与线程池的基本原理 1201)、线程 1202)、线程的生命周期 1213)、什么是单线程和多线程 1214)、线程池 1225)、四种常见的线程池 123线程池的架构与流程 123线程池代码实战 125    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大雨淅淅

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值