当前位置:首页 » 《资源分享》 » 正文

C++

8 人参与  2024年12月07日 12:02  分类 : 《资源分享》  评论

点击全文阅读


   目录

C++ 的发展总结:​编辑

1. C++ 的早期发展(1979-1985)

2. C++ 标准化过程(1985-1998)

3. C++ 标准演化(2003-2011)

4. C++11(2011年)

5. C++14(2014年)

6. C++17(2017年)

7. C++20(2020年)

8. C++23(2023年)

1. C++ 1985: C++ 1.0

主要特性:

示例代码:

代码讲解:

C++ 1.0 的局限性:

总结:

2. C++ 1989: C++ 2.0

主要特性:

多重继承与虚继承

示例代码:

代码讲解:

运行输出:

解释:

C++ 2.0 的局限性:

总结:

3. C++ 1990: C++ 3.0

主要特性:

模板的引入

示例代码:模板示例

代码讲解:

运行输出:

代码解释:

模板的优势:

C++ 3.0 的局限性:

总结:

4. C++ 1998: C++98

主要特性:

示例代码:C++98 的常见特性

代码讲解:

运行输出:

代码解释:

C++98 的局限性:

总结:

5. C++ 2003: C++03

主要特性和变化:

C++03 与 C++98 的区别:

示例代码:C++98 和 C++03 的差异

示例代码:模板特化修复和 SFINAE 改进

代码解释:

运行输出:

C++03 与 C++98 的局限性:

总结:

6. C++ 2011: C++11

主要新特性:

示例代码:C++11 特性

代码解释:

运行输出:

C++11 的优势:

C++11 的局限性:

总结:

7. C++ 2014: C++14

主要新特性:

示例代码:C++14 新特性

代码解释:

运行输出:

C++14 的优势:

C++14 的局限性:

总结:

8. C++ 2017: C++17

1. 结构化绑定声明 (Structured Bindings)

示例:

2. if/else语句中的初始化语句 (If/else with initialization)

示例:

3. std::optional

示例:

4. std::string_view

示例:

5. std::filesystem

示例:

6. 并行算法 (Parallel Algorithms)

示例:

7. 内联变量 (Inline Variables)

示例:

8. 改进的constexpr

示例:

总结

9. C++ 2020: C++20

1. 概念 (Concepts)

示例:

2. 范围 (Ranges)

示例:

3. 协程 (Coroutines)

示例:

4. 三向比较 (Spaceship Operator <=>)

示例:

5. 模块 (Modules)

示例:

6. 范围循环 (Range-based for loop with initializer)

示例:

7. std::span

示例:

8. consteval 和 constinit

示例:

总结

10. C++ 2023: C++23

1. 改进的常量表达式(constexpr)

示例:

2. std::expected

示例:

3. 范围(Ranges)库增强

示例:

4. std::format 改进

示例:

5. explicit 改进

示例:

6. std::span 支持的改进

示例:

7. 新的属性([[likely]] 和 [[unlikely]])

示例:

总结

C++ 的发展总结:

C++ 是由 Bjarne Stroustrup 于 1979 年在贝尔实验室(Bell Labs)开始开发的,最初是作为 C 语言的一个扩展,目的是在不丧失 C 语言高效性的基础上,提供面向对象编程的特性。C++ 的发展历程可以分为以下几个重要阶段:

C++ 的早期发展1979-1985
C++ 标准化过程1985-1998
C++ 标准演化2003-2011
C++112011年
C++142014年
C++172017年
C++202020年
C++232023年

1. C++ 的早期发展(1979-1985)

1979年:C++ 的前身 "C with Classes" 出现。Bjarne Stroustrup 在贝尔实验室的工作中,设计了一个扩展 C 语言的工具,该工具为 C 语言增加了类(class)、构造函数和析构函数等面向对象特性。它的设计目标是提高程序的可重用性,并通过封装数据和方法的方式增强程序结构。1983年:C with Classes 更名为 **C++**,并发布了第一版 C++ 语言,开始引入类、继承、多态等面向对象的特性,虽然这些特性并不完善,但已经为后来的发展奠定了基础。1985年:C++ 语言的第一个标准版本发布。Stroustrup 为此编写了《C++ Programming Language》一书,详细介绍了 C++ 的语法、特性和编程模型。

2. C++ 标准化过程(1985-1998)

1989年:C++ 的第一个国际标准草案发布,作为一种较为成熟的语言,逐渐被越来越多的开发者使用。1990年:C++ 被纳入国际标准化组织(ISO)的标准化过程。这个过程中,C++ 逐步加入了更多的语言特性,如模板、异常处理、名字空间等。1998年:C++98 标准发布,这是 C++ 语言的第一个正式标准版本。C++98 通过增加模板支持、标准库(如 STL)和异常处理机制,使得 C++ 语言更加全面和功能强大,成为当时最主流的编程语言之一。

3. C++ 标准演化(2003-2011)

2003年:C++03 标准发布,主要是对 C++98 标准的修正和小幅改进,修复了一些语言特性中的小错误,并未引入重大的新特性。2007年:ISO 发布了 C++0x 标准草案,该标准最终演变为 C++11。在 C++0x 的过程中,许多新的特性开始得到提出和采纳,如 自动类型推导右值引用lambda 表达式并发编程 等。C++11 的标准化过程历时多年,经历了大量的讨论和修改。

4. C++11(2011年)

2011年:C++11 正式发布,它是 C++ 语言的一个重大变革,包含了大量的新特性,标志着 C++ 语言进入了一个全新的时代。C++11 的主要特性包括: 自动类型推导auto);右值引用移动语义&&std::move);Lambda 表达式线程支持std::thread);智能指针std::unique_ptrstd::shared_ptr);类型推导decltype)等。C++11 的引入极大提升了 C++ 语言的表达力和现代化程度,使得 C++ 编程更具灵活性和高效性。

5. C++14(2014年)

2014年:C++14 发布,相较于 C++11,C++14 更像是一个小规模的优化和修复版本。C++14 主要增强了 C++11 中的特性,如 Lambda 表达式的泛型支持、std::make_unique 的引入、decltype(auto) 的改进等。此外,还修复了一些编译器和实现中的问题。C++14 让 C++11 中的很多新特性变得更加稳定,增加了可编程性和工具支持。

6. C++17(2017年)

2017年:C++17 发布,这个版本包含了一些有意义的语言特性和标准库增强。主要特性包括: **std::optional**:用于表示可能为空的值;结构化绑定声明auto [a, b] = tuple;);if 和 switch 中的初始化语句;**std::filesystem**:用于处理文件和目录的标准库;**改进的 std::string 和 std::array**;并行算法std::for_each 等支持并行执行)。C++17 不仅增强了语言本身的功能,还进一步加强了对现代硬件和多核处理器的支持,增强了性能和并行计算能力。

7. C++20(2020年)

2020年:C++20 发布,是 C++ 语言历史上一个非常重要的版本,带来了许多令人兴奋的新特性: 模块(Modules):改善头文件管理,减少编译时间;三方比较操作符<=>): 用于自动生成比较操作符(比如 ==!=<<=>>=);协程(Coroutines):使得异步编程更加简洁;概念(Concepts):提供更强的类型约束机制,使模板编程更加安全;范围 for 循环改进:更简洁的语法和强大的灵活性;**std::span**:处理数组和内存块的轻量级对象;改进的标准库:包括 std::formatstd::rangesstd::calendar 等。C++20 为 C++ 带来了大量的现代化特性,并进一步提升了语言的表达能力、性能和并发编程的支持。

8. C++23(2023年)

2023年:C++23 发布,虽然其变化相较于 C++20 比较平稳,但仍然包含了一些重要的改进和修复: 新的标准库功能:例如,std::expectedstd::generator 和 std::ranges 的进一步改进;语言增强:对模板和类型推导的改进,增强了语言的灵活性和可读性;性能优化:进一步增强编译器对并行、异步和内存管理的支持。C++23 标志着 C++ 语言持续向现代化发展,并且对性能和并发编程的支持进一步加强。

从面向过程到面向对象:最初的 C++ 语言只是在 C 语言的基础上增加了类和面向对象的特性,经过多年发展,C++ 在保留 C 语言高效性的同时,也吸收了面向对象、泛型编程和函数式编程的优势,成为了一门多范式的语言。

标准化过程:从 C++98 到 C++11,再到 C++14、C++17 和 C++20,C++ 逐渐成为一种具有广泛应用的编程语言,每个版本都带来了一些新的特性和增强,逐步适应现代软件开发的需求。

现代化与性能:C++ 在引入面向对象特性后,也逐步加入了并行计算、内存管理、泛型编程、协程等现代编程特性,使得它在高性能计算、系统开发、游戏开发和金融等领域仍然占有一席之地。

C++ 的发展历程体现了它强大的灵活性和持久生命力,C++ 不断演进,始终保持着与时俱进的能力,成为全球使用最广泛的编程语言之一。

C++ 的发展历程可以分为多个版本阶段,每个版本都带来了新的语言特性、库的改进和标准的增强。下面是 C++ 各个版本的主要变化和特性介绍:

1. C++ 1985: C++ 1.0

最初版本:由贝尔实验室的 Bjarne Stroustrup 在 1980 年代初期开发。主要特点: 在 C 语言的基础上加入了面向对象编程(OOP)特性。支持类、继承、多态、封装等面向对象的基本特性。引入了函数和运算符重载。

C++ 1.0 是由 Bjarne Stroustrup 在贝尔实验室开发的第一版 C++ 编程语言。它是在 C 语言的基础上加入了面向对象编程(OOP)的特性,因此也被称为是“C with Classes”(C 带类)。C++ 1.0 并不是一个标准化的语言版本,而是一个实验性语言,它为后来的 C++ 标准奠定了基础。

主要特性:

类与对象:C++ 1.0 引入了面向对象编程的核心概念,最初的类和对象支持比较简单。

类是 C++ 中的基本构造,用于封装数据和功能。对象是类的实例,表示实际的数据和行为。

函数和运算符重载:C++ 1.0 支持函数重载和运算符重载,使得程序员可以根据需要定义不同版本的函数或操作符。

基本继承:C++ 1.0 支持从一个类继承另一个类,使得可以构建更为复杂的类结构。

无标准库:当时的 C++ 语言没有像现代 C++ 那样的标准库。数据结构和算法通常依赖开发者自己编写。

示例代码:

C++ 1.0 版本的代码相对简单。以下是一个典型的 C++ 1.0 示例,演示了类的定义、对象创建、继承以及运算符重载。

#include <iostream>using namespace std;// 定义一个类class Box {private:    double length;   // 长度    double breadth;  // 宽度    double height;   // 高度public:    // 构造函数    Box(double l, double b, double h) {        length = l;        breadth = b;        height = h;    }    // 计算体积的方法    double volume() {        return length * breadth * height;    }    // 运算符重载    Box operator+(const Box& b) {        // 返回一个新的 Box 对象,体积相加        return Box(length + b.length, breadth + b.breadth, height + b.height);    }};// 主函数int main() {    // 创建对象    Box box1(3.5, 1.2, 2.0);    Box box2(1.0, 2.0, 3.0);    // 计算并输出 box1 的体积    cout << "Box1 Volume: " << box1.volume() << endl;    // 运算符重载使用示例    Box box3 = box1 + box2;    cout << "Box3 Volume (box1 + box2): " << box3.volume() << endl;    return 0;}

代码讲解:

**类 Box**:定义了一个包含 lengthbreadth 和 height 的类,用于表示一个盒子,并且提供了一个计算体积的方法 volume()构造函数:用于初始化 Box 对象,设置它的长度、宽度和高度。运算符重载:使用 operator+ 重载运算符 +,使得两个 Box 对象相加时,返回一个新的 Box 对象,长度、宽度和高度分别相加。在 main() 中创建对象:通过构造函数创建了 box1 和 box2,并计算它们的体积。在计算 box3 的体积时,使用了重载的加法运算符。

C++ 1.0 的局限性:

缺少模板:当时的 C++ 并不支持模板(泛型编程),模板编程是后来在 C++ 1990 和 1998 标准中引入的。没有标准库:没有现代 C++ 的 STL(标准模板库),因此没有常用的容器、算法等功能。继承的支持较为基础:C++ 1.0 支持继承,但还没有引入多态、虚函数等更高级的特性。

总结:

C++ 1.0 是 C++ 语言的初步版本,它为面向对象编程提供了基础设施,并通过类、对象、继承、重载等功能扩展了 C 语言的功能。虽然当时的 C++ 功能较为简单,但它为后续版本的语言特性打下了基础,并引领了 C++ 向更强大的方向发展。

2. C++ 1989: C++ 2.0

增强功能多重继承:支持多个基类的继承。虚继承:解决多重继承中的“菱形继承”问题,确保继承层次中的基类只有一份副本。抽象类:引入了纯虚函数(抽象类)的概念,使得类能够定义接口。

C++ 2.0 是 C++ 语言的第二个重要版本,发布于 1989 年。C++ 2.0 在 C++ 1.0 的基础上进行了重要的扩展和改进,引入了多个新特性,特别是 多重继承 和 虚继承。这些新特性使得 C++ 的面向对象编程能力得到了显著增强。C++ 2.0 为后来的 C++ 语言标准奠定了许多重要基础。

主要特性:
多重继承:C++ 2.0 引入了多重继承的支持,使得一个类可以继承多个基类,从而可以组合多个类的功能。虚继承:为了解决多重继承带来的“菱形继承”问题(即一个类通过多个继承路径继承同一个基类),C++ 2.0 引入了 虚继承 的概念。虚继承确保通过多个继承路径继承的同一个基类只有一份副本。虚函数:继续扩展了对面向对象编程的支持,尤其是通过 虚函数 机制,使得 C++ 支持 运行时多态更强的类型检查:C++ 2.0 对类型检查进行了增强,使得语言的类型系统更加严格和安全。

多重继承与虚继承

C++ 2.0 的最大变化之一就是支持 多重继承,并且引入了 虚继承 来解决多重继承可能引起的问题。在多重继承中,如果一个类继承自多个基类,并且这些基类有公共的祖先类,那么在派生类中会有重复的祖先类副本,这时就可能出现问题。虚继承解决了这一问题,通过确保只有一个祖先类副本,从而避免了数据冗余和潜在的错误。

示例代码:

以下是一个简单的示例,演示了 多重继承 和 虚继承 的概念。

#include <iostream>using namespace std;// 基类Aclass A {public:    A() { cout << "Class A constructor" << endl; }    void showA() { cout << "Class A" << endl; }};// 基类Bclass B {public:    B() { cout << "Class B constructor" << endl; }    void showB() { cout << "Class B" << endl; }};// 基类C,虚继承Aclass C : virtual public A {public:    C() { cout << "Class C constructor" << endl; }    void showC() { cout << "Class C" << endl; }};// 派生类D,虚继承A和Bclass D : public C, public B {public:    D() { cout << "Class D constructor" << endl; }    void showD() { cout << "Class D" << endl; }};int main() {    // 创建派生类对象D    D d;    d.showA(); // 来自基类A    d.showB(); // 来自基类B    d.showC(); // 来自基类C    d.showD(); // 来自派生类D    return 0;}

代码讲解:

类 A 和 BA 和 B 是两个基类,都有自己的构造函数和成员函数。A 有一个 showA() 函数,B 有一个 showB() 函数。类 CC 类继承了 A 类,并使用 virtual 关键字进行 虚继承。这样,在 C 的子类中,如果有多个继承自 A 的路径,它们会共享同一个 A 类副本,避免了重复数据。类 DD 类从 C 和 B 继承,并且通过虚继承机制共享了 A 类的副本。输出: 当 D 类的对象被创建时,首先调用 AB 和 C 的构造函数,再调用 D 的构造函数。showA()showB() 和 showC() 分别调用了从基类继承的成员函数。

运行输出:

Class A constructorClass B constructorClass C constructorClass D constructorClass AClass BClass CClass D

解释:

虚继承C 类通过 virtual public A 虚继承了 A 类,保证了通过 D 类的继承关系,A 类只有一份副本。即使 D 类是通过 B 和 C 两个路径继承 AA 类也只会被构造一次。多重继承D 类通过多重继承继承了 B 和 C,因此 D 类拥有 B 和 C 类的功能。

C++ 2.0 的局限性:

没有命名空间:C++ 2.0 并没有引入命名空间(namespace),因此容易出现命名冲突的问题。没有模板支持:模板编程(如函数模板和类模板)在 C++ 2.0 中还没有出现,这一特性是在 C++ 3.0 中引入的。继承体系较为简化:虽然支持多重继承和虚继承,但对继承体系的支持仍较为基础,随着 C++ 后续版本的发布,继承和多态的功能会得到更完善的支持。

总结:

C++ 2.0 通过引入 多重继承 和 虚继承 大大增强了 C++ 的面向对象能力,使得 C++ 成为一种更强大的编程语言。这些特性让 C++ 能够支持更复杂的类层次结构,解决了多重继承中的一些难题。虽然 C++ 2.0 语言仍然很基础,但它为 C++ 后续版本的更高级特性,如模板和更复杂的类型系统,奠定了基础。

3. C++ 1990: C++ 3.0

功能增强模板:引入了模板(函数模板和类模板),开始支持泛型编程。标准库:初步支持了标准模板库(STL)的概念,虽然 STL 直到后来的版本才成为标准。

C++ 3.0 是 C++ 语言的第三个版本,发布于 1990 年。相比于前两个版本,C++ 3.0 在语言特性和功能上做出了重要的扩展,最为关键的就是引入了 模板 的支持,这是 C++ 语言向 泛型编程 过渡的重要一步。模板的引入使得 C++ 支持编写与类型无关的代码,从而使得编程变得更加灵活和强大。

主要特性:

模板(Templates)

函数模板:允许定义可以接受不同类型参数的函数。类模板:允许定义可以接受不同类型参数的类。模板是 C++ 语言中泛型编程的基础。

增强的类型系统

支持更复杂的类型定义和类型推导。改进了类和对象的类型推断机制。

基本的标准库(STL的雏形)

尽管 C++ 3.0 本身并没有正式定义标准模板库(STL),但它开始支持类似 STL 的一些容器和算法概念,为未来 STL 的引入奠定了基础。

支持虚函数、运算符重载等特性

C++ 3.0 继续扩展了面向对象编程的支持,增强了对继承、多态、运算符重载等特性的支持。

模板的引入

C++ 3.0 的核心改进就是引入了模板机制,使得函数和类能够接受参数类型作为模板参数。这使得 C++ 能够支持泛型编程,从而能够编写类型安全且重用性更高的代码。

示例代码:模板示例

以下是一个简单的示例,展示了如何在 C++ 3.0 中使用 函数模板 和 类模板

#include <iostream>using namespace std;// 函数模板:计算两个数字的最大值template <typename T>T getMax(T a, T b) {    return (a > b) ? a : b;}// 类模板:定义一个简单的容器类template <typename T>class Box {private:    T value;public:    Box(T v) : value(v) {}    T getValue() { return value; }    void setValue(T v) { value = v; }};int main() {    // 使用函数模板    int x = 10, y = 20;    cout << "Max of x and y: " << getMax(x, y) << endl;    double a = 3.14, b = 2.71;    cout << "Max of a and b: " << getMax(a, b) << endl;    // 使用类模板    Box<int> intBox(100);    cout << "Box contains: " << intBox.getValue() << endl;    intBox.setValue(200);    cout << "Updated Box contains: " << intBox.getValue() << endl;    Box<double> doubleBox(3.14159);    cout << "Box contains: " << doubleBox.getValue() << endl;    return 0;}

代码讲解:

**函数模板 getMax**:

getMax 是一个函数模板,它接受两个类型为 T 的参数,返回它们中的最大值。T 是一个类型参数,可以是任何数据类型(如 intdouble 等),当调用模板函数时,编译器会根据传入的参数类型推导出 T 的具体类型。

**类模板 Box**:

Box 是一个类模板,它有一个类型为 T 的成员变量 value。构造函数接受一个 T 类型的参数来初始化 value,并提供了 getValue 和 setValue 方法来访问和修改 value

运行输出:

Max of x and y: 20Max of a and b: 3.14Box contains: 100Updated Box contains: 200Box contains: 3.14159

代码解释:

getMax 函数模板:在 main() 中,分别使用了 int 和 double 类型的参数来调用 getMax 函数模板。编译器根据传入的参数类型推导出 T 的类型。Box 类模板Box<int> 和 Box<double> 分别是使用 int 和 double 类型的类模板实例化出来的对象。每个 Box 对象可以存储不同类型的数据。

模板的优势:

代码重用:通过模板,函数和类可以支持多种不同的类型,而不需要为每个类型编写重复的代码。类型安全:模板在编译时进行类型检查,确保类型的正确性,避免了运行时的类型错误。

C++ 3.0 的局限性:

模板特性较为基础:C++ 3.0 中的模板机制较为简单,没有现代 C++ 中复杂的模板特性,如模板特化、SFINAE(Substitution Failure Is Not An Error)等。标准库仍然不成熟:尽管模板提供了更多的灵活性,但标准库并没有像 C++11 和 C++14 中那样强大,STL 的概念才刚刚开始萌芽。

总结:

C++ 3.0 是 C++ 语言的一个重要版本,模板的引入是其最大的亮点,标志着 C++ 进入了泛型编程的时代。模板让 C++ 变得更加灵活,支持更加高效的代码重用和类型安全的操作。通过函数模板和类模板,C++ 可以在不同类型之间共享代码,从而极大地提高了开发效率和代码的可维护性。虽然 C++ 3.0 的模板机制相对简单,但它为后续的 C++ 标准化进程和更复杂的模板特性奠定了基础。

4. C++ 1998: C++98

C++ 标准化:C++98 是 C++ 的第一个正式标准版本,由 ISO/IEC 14882:1998 定义。主要特性STL(标准模板库):引入了标准模板库,包括 vectorlistmapset 等容器,及算法(如排序、查找等)。map - C++ Reference    set - C++ Reference命名空间(namespace):为了避免名称冲突,引入了命名空间。异常处理:引入了 trycatchthrow 异常处理机制。RTTI(运行时类型信息):引入了 typeid 和 dynamic_cast,允许运行时识别对象的类型。

C++98 是 C++ 语言的第一个国际标准,正式由 ISO(国际标准化组织)在 1998 年发布。C++98 语言标准继承了 C++ 3.0 的核心特性,并在此基础上进行了多个重要的改进和规范化。这个版本的 C++ 为标准库(STL)提供了规范,并开始支持更多的现代编程特性。

主要特性:

模板

C++98 中的模板特性得到了进一步的增强,支持函数模板和类模板,并且模板的使用变得更加广泛。模板参数可以是类、函数、指针等类型。

标准模板库(STL)

sort - C++ Reference

异常处理

C++98 提供了标准化的异常处理机制,使用 trycatchthrow 语句来处理运行时错误。

命名空间

C++98 引入了 命名空间namespace),用于避免名称冲突,尤其是在大型项目中。

虚函数与多态

C++98 继续强化了面向对象编程的支持,特别是对 虚函数 和 多态 的使用。

const 和引用

C++98 对 const 关键字和引用进行了严格的规范,使得编程更加安全。

函数指针和类型转换

提供了对 函数指针 和 类型转换(如 static_castdynamic_cast 等)的支持,增强了 C++ 的灵活性。

类成员的类型推导

C++98 引入了对类成员类型的推导,允许在某些情况下省略类型声明。
示例代码:C++98 的常见特性

以下是一个综合示例,展示了 C++98 中的几个核心特性,包括模板、标准库(STL)、命名空间和异常处理。

vector - C++ Reference

#include <iostream>#include <vector>#include <algorithm>#include <stdexcept>namespace MyNamespace {    // 模板函数:计算两个数的最大值    template <typename T>    T getMax(T a, T b) {        return (a > b) ? a : b;    }    // 使用 STL 容器:vector 和算法    void useSTL() {        std::vector<int> vec = {3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5};        std::sort(vec.begin(), vec.end());                std::cout << "Sorted vector: ";        for (int num : vec) {            std::cout << num << " ";        }        std::cout << std::endl;    }    // 异常处理示例    void testException() {        try {            throw std::out_of_range("Index out of range!");        } catch (const std::exception& e) {            std::cout << "Caught exception: " << e.what() << std::endl;        }    }}int main() {    // 使用命名空间    using namespace MyNamespace;    // 使用模板函数    int x = 10, y = 20;    std::cout << "Max of x and y: " << getMax(x, y) << std::endl;    // 使用 STL 容器和算法    useSTL();    // 测试异常处理    testException();    return 0;}

代码讲解:

**模板函数 getMax**:

这是一个简单的模板函数,接受两个相同类型的参数,并返回它们中的最大值。typename T 表示这是一个模板函数,T 是占位符类型,可以在调用时由编译器自动推导出。

STL 容器和算法

在 useSTL 函数中,使用了 std::vector 来存储整数数据,并使用 std::sort 算法对数据进行了排序。std::vector 是 C++98 标准库中的一个动态数组容器,std::sort 是一个算法函数,用于对容器中的元素进行排序。

异常处理

testException 函数演示了 C++98 的异常处理机制。在这个函数中,抛出了一个 std::out_of_range 异常,并在 catch 块中捕获它,输出异常的描述信息。

运行输出:

Max of x and y: 20Sorted vector: 1 1 2 3 3 4 5 5 5 6 9 Caught exception: Index out of range!

代码解释:

**模板 getMax**:通过模板,可以在运行时自动确定 T 的类型,支持不同的数据类型(如 intdouble 等)。在本例中,它比较了两个整数 x 和 y。**STL 容器 std::vector 和 std::sort**:std::vector 是一个可以动态调整大小的容器,它存储一系列元素。std::sort 是一个通用算法,用来对容器中的元素进行排序。异常处理:C++98 提供了标准的异常处理机制,允许在代码运行过程中抛出和捕获异常,避免程序因错误而崩溃。

C++98 的局限性:

没有 auto 关键字:C++98 中没有 auto 关键字,因此类型推导只能依靠显式的类型声明。**没有 nullptr**:C++98 中没有 nullptr,指针使用时可能会引发隐式的类型转换问题。没有类型推导的 for 循环:C++98 中没有像 C++11 中那样的基于范围的 for 循环(for (auto& elem : container))。模板元编程有限:虽然模板功能在 C++98 中已被引入,但对于模板元编程的支持相对有限,模板编程的复杂性和灵活性较低。

总结:

C++98 是 C++ 语言的第一个国际标准版本,它巩固并标准化了之前 C++3.0 中的许多特性,并加入了 模板 和 STL 等重要特性,使得 C++ 在实际开发中更加高效和灵活。通过模板,C++98 使得代码可以在不同的数据类型之间重用,同时标准库(STL)提供了高效的容器和算法支持,大大提高了开发效率。虽然 C++98 为后来的 C++ 标准奠定了基础,但它在某些领域(如模板编程和自动类型推导)仍存在局限。

5. C++ 2003: C++03

修复和改进小的改进:C++03 主要是对 C++98 标准的一些修订和错误修正,没有引入重大新特性。支持一些新的编译器特性,如增强的模板支持、异常安全性等。

C++03 是 C++ 语言的一个小版本更新,它是对 C++98 的修正版本,主要用于解决一些语言上的不一致性和设计上的小问题。C++03 并未引入许多新的功能,而是对 C++98 标准中的一些细节进行了修正和澄清,确保语言的一致性和规范性。这个版本主要集中在语言规范的完善和一些编译器支持方面。

C++03 的发布并没有像 C++98 到 C++11 之间的版本那样进行革命性的更新,因此它在功能上与 C++98 并无太大差异。主要的更新包括对 模板特化SFINAE(Substitution Failure Is Not An Error)等方面的细节修正,确保了编译器能够更好地支持标准库。

主要特性和变化:

模板的修正和改进

C++03 对模板特化和模板元编程做了小的修正,使得编译器对模板的支持更加一致。改进了模板在某些边界情况中的行为,避免了 C++98 中一些不一致或令人困惑的部分。

标准库的修正

C++03 对标准库中的一些接口做了微调,解决了 C++98 标准库中的一些小问题。例如,修复了 std::vector 在某些情况下的行为不一致性,确保了 STL 中的算法与容器的更好兼容性。

修复了常见的编译器问题

C++03 对一些编译器的兼容性问题进行了修复,确保不同厂商的编译器之间有更好的兼容性。

去除了某些不再使用的特性

C++03 删除了一些在 C++98 中冗余或未被广泛使用的特性,从而使标准更加精简和一致。

C++03 与 C++98 的区别:

细节修正:C++03 主要是针对 C++98 标准中存在的某些歧义性和编译器实现差异进行修正。它并没有加入新的语言特性,而是专注于优化语言和标准库的现有特性。STL 和模板的完善:C++03 解决了模板和标准库的一些小问题,确保标准库在不同编译器下的行为一致。

示例代码:C++98 和 C++03 的差异

由于 C++03 与 C++98 的差异主要体现在语言的细节上,因此以下示例代码在 C++03 中的表现与 C++98 是相同的。我们展示一些在 C++98 和 C++03 中模板使用的常见问题,这些问题在 C++03 中得到了修正。

示例代码:模板特化修复和 SFINAE 改进
#include <iostream>#include <type_traits>// 模板类的默认实现template <typename T>class Printer {public:    static void print(const T& value) {        std::cout << value << std::endl;    }};// 特化:对于 const 类型的处理template <typename T>class Printer<const T> {public:    static void print(const T& value) {        std::cout << "const value: " << value << std::endl;    }};// 使用 SFINAE 来选择函数template <typename T>typename std::enable_if<!std::is_integral<T>::value, void>::typeprintType(const T& value) {    std::cout << "Non-integer value: " << value << std::endl;}template <typename T>typename std::enable_if<std::is_integral<T>::value, void>::typeprintType(const T& value) {    std::cout << "Integer value: " << value << std::endl;}int main() {    Printer<int>::print(123);  // 默认模板    Printer<const int>::print(456);  // 特化模板    printType(123);  // 调用整数版本    printType(3.14);  // 调用非整数版本    return 0;}

代码解释:

模板类 Printer 的特化

Printer 是一个模板类,在默认情况下,它的 print 函数打印任意类型的值。特化版本 Printer<const T> 对 const 类型的处理进行了特殊化,使其输出时带有 "const value: " 字样。此特化是在 C++03 中明确规定的,确保了特化行为的统一性。

SFINAE(Substitution Failure Is Not An Error)

printType 函数使用了 SFINAE 来根据类型 T 的不同选择不同的版本。

使用 std::enable_if 和 std::is_integral 来判断 T 是否为整数类型,并分别调用不同的函数。SFINAE 机制可以避免无效的模板实例化,确保了代码的类型安全。

如果 T 是整数类型,printType(int) 会被调用;否则,printType(double) 会被调用。

运行输出:

123const value: 456Integer value: 123Non-integer value: 3.14

C++03 与 C++98 的局限性:

没有新的语言特性:C++03 仅仅是 C++98 的修正版本,没有引入新的语言特性。开发者并未从中获得像 C++11、C++14、C++17 那样的重大进展。标准库的改进有限:虽然 C++03 修复了一些标准库的问题,但与后来的 C++ 标准相比,它的功能仍显得较为简单。没有现代化工具:如 autonullptr、范围 for 循环等特性都没有出现在 C++03 中,这使得它在一些现代编程需求面前显得有些过时。

总结:

C++03 是一个对 C++98 的修正版本,主要修复了一些语言规范中的小错误和不一致性,改进了模板、STL 和编译器的兼容性。它并没有引入新的语言特性,因此在实际使用中,C++98 和 C++03 的差异并不显著。C++03 主要对 C++98 的一些不明确之处进行了修正,为后续 C++ 标准的进化(如 C++11、C++14)奠定了基础。对于开发者来说,C++03 更多的是一种稳定性和兼容性更新,而不是一种功能性扩展。

6. C++ 2011: C++11

现代 C++ 的起点:C++11 是 C++ 的一次重大更新,被广泛认为是 C++ 语言的“现代化”转折点。关键特性: 自动类型推断(auto):使用 auto 关键字可以让编译器推断变量类型。智能指针:引入了 std::unique_ptrstd::shared_ptrstd::weak_ptr,用于自动管理内存,避免内存泄漏。Lambda 表达式:允许定义匿名函数,可以在代码中更方便地使用函数对象。并发支持:引入了 <thread> 库,允许多线程编程。**nullptr**:引入了 nullptr 关键字,替代 NULL,提高代码的类型安全。右值引用和移动语义:引入右值引用(&&)和 std::move,提高对象传递效率,减少不必要的拷贝。范围 for 循环:引入了简洁的范围 for 循环,简化容器遍历。类型别名(using):引入 using 关键字,简化类型别名定义。变长模板(Variadic Templates):支持可变参数模板,提高模板的灵活性。

C++11 是 C++ 语言的一个重大更新,正式于 2011 年发布。它引入了大量新的特性和改进,使 C++ 语言更现代化、更加高效和易于使用。C++11 标准的推出,极大地扩展了 C++ 的功能,使得 C++ 开发变得更加灵活、简洁,同时还提升了性能。

主要新特性:

自动类型推导(auto

auto 关键字允许编译器根据表达式的类型自动推导变量的类型,减少了类型声明的冗余,提高了代码可读性。

右值引用与移动语义(&& 和 std::move

引入右值引用(&&)和 std::move,实现了 移动语义。通过移动资源而不是复制,显著提高了效率,尤其在需要大量数据传输的场合(如容器操作)。

范围 for 循环

引入了范围 for 循环(range-based for loop),简化了容器元素的遍历,避免了传统迭代器的复杂性。

Lambda 表达式

Lambda 表达式允许在函数内定义匿名函数,并且可以捕获外部变量,极大地增强了函数式编程的支持。

**nullptr**:

nullptr 替代了 NULL,它是一个类型安全的空指针常量,消除了 NULL 的类型不匹配问题。

**constexpr**:

constexpr 使得可以在编译时求值的常量表达式更加简洁,增强了编译期计算的能力。

并发编程:<thread> 库

C++11 引入了原生的线程支持,<thread> 库使得多线程编程变得更加容易和高效。

类型别名(using

using 关键字可以用来为类型定义别名,取代了传统的 typedef,语法更加简洁。

强类型枚举(enum class

引入了强类型枚举 enum class,避免了传统枚举可能产生的隐式转换和命名冲突问题。

**新标准库:std::chrono**:

C++11 引入了用于处理时间和日期的新标准库 std::chrono,使得处理时间变得更加直观和精确。

示例代码:C++11 特性

下面的代码示例展示了 C++11 的一些关键特性。

#include <iostream>#include <vector>#include <algorithm>#include <thread>#include <functional>// 1. 自动类型推导void autoExample() {    auto x = 10;  // 编译器自动推导类型为 int    auto y = 3.14;  // 编译器自动推导类型为 double    std::cout << "x: " << x << ", y: " << y << std::endl;}// 2. 范围 for 循环void rangeBasedFor() {    std::vector<int> vec = {1, 2, 3, 4, 5};    for (auto& num : vec) {  // 使用范围 for 遍历        num *= 2;    }    std::cout << "Doubled values: ";    for (const auto& num : vec) {        std::cout << num << " ";    }    std::cout << std::endl;}// 3. Lambda 表达式void lambdaExample() {    std::vector<int> vec = {1, 2, 3, 4, 5};    int sum = 0;    // 使用 lambda 表达式进行求和    std::for_each(vec.begin(), vec.end(), [&sum](int num) { sum += num; });    std::cout << "Sum of elements: " << sum << std::endl;}// 4. 移动语义和右值引用class MyClass {public:    MyClass() { std::cout << "Constructor\n"; }    MyClass(const MyClass&) { std::cout << "Copy Constructor\n"; }    MyClass(MyClass&&) { std::cout << "Move Constructor\n"; }    MyClass& operator=(const MyClass&) { std::cout << "Copy Assignment\n"; return *this; }    MyClass& operator=(MyClass&&) { std::cout << "Move Assignment\n"; return *this; }};void moveExample() {    MyClass a;    MyClass b = std::move(a);  // 使用移动构造函数}int main() {    // 自动类型推导    autoExample();    // 范围 for 循环    rangeBasedFor();    // Lambda 表达式    lambdaExample();    // 移动语义    moveExample();    // 使用线程    std::thread t([]{ std::cout << "Hello from a thread!\n"; });    t.join();  // 等待线程执行完毕    return 0;}

代码解释:

**自动类型推导 (auto)**:

使用 auto 关键字,编译器会自动推导变量 x 和 y 的类型,简化了类型声明,特别是对于复杂类型(如迭代器和函数返回类型)时非常有用。

范围 for 循环

使用 C++11 引入的范围 for 循环来遍历容器。这个语法简洁、直观,避免了显式的迭代器操作。

Lambda 表达式

使用 std::for_each 算法与 lambda 表达式结合,计算容器中所有元素的总和。lambda 表达式 [&sum](int num) { sum += num; } 捕获外部变量 sum 并对容器中的每个元素执行加法操作。

右值引用与移动语义

在 moveExample 中,通过 std::move 实现了对象 a 的移动,将其资源转移给对象 b,触发了移动构造函数而不是拷贝构造函数。

线程支持

使用 C++11 的 <thread> 库创建和启动一个线程,并且通过 join() 等待线程执行完成。std::thread 简化了多线程编程。

运行输出:

x: 10, y: 3.14Doubled values: 2 4 6 8 10Sum of elements: 15Move ConstructorHello from a thread!

C++11 的优势:

现代化的语法和功能:C++11 引入的众多新特性大大提升了语言的灵活性和表达力,减少了冗余代码,使得 C++ 编程更加简洁、易读和高效。性能优化:通过右值引用和移动语义,C++11 使得许多数据传输和复制操作得以高效地优化,特别是在容器和大型对象的操作中,性能大幅提升。并发支持:C++11 将多线程支持纳入语言标准,使得并发编程变得更加容易和可靠,减少了对外部库的依赖。

C++11 的局限性:

学习曲线:尽管 C++11 引入了许多现代化特性,但对一些开发者来说,掌握这些新特性可能需要一定的学习时间。编译器支持问题:尽管大部分现代编译器已经完全支持 C++11,但一些旧的编译器或开发环境可能存在兼容性问题。

总结:

C++11 是 C++ 语言的一次重大更新,带来了许多新的语言特性和库支持,使得 C++ 编程变得更加简洁、强大和高效。无论是在性能优化、现代语法的引入,还是在并发支持等方面,C++11 都大幅提升了语言的可用性和表达能力。

7. C++ 2014: C++14

小幅增强: constexpr 的改进:支持更复杂的编译时常量计算。二进制字面量:引入了支持二进制常量字面量。auto 的增强:使得 auto 可以推导更加复杂的类型。Lambda 表达式的改进:支持更强的捕获特性(如捕获 *this 引用)。

C++14 是 C++ 语言的一个相对较小的更新版本,于 2014 年发布。C++14 并没有像 C++11 那样引入大量的新特性,而是对 C++11 中的一些特性进行了修复、增强和小幅优化。它的目标是提高语言和标准库的稳定性,改进一些 C++11 的边界情况,增强编译器的支持,并提供一些性能上的提升。

主要新特性:

泛型 Lambda 表达式

C++14 扩展了 C++11 中的 Lambda 表达式,引入了泛型 Lambda,使得 Lambda 可以接受不同类型的参数而不需要显式地指定类型。

变量模板

C++14 引入了 变量模板,允许创建像模板函数一样的模板变量。之前只有函数和类可以是模板,但 C++14 使得变量也可以具有模板特性。

Lambda 表达式的返回类型推导

在 C++14 中,Lambda 表达式可以通过 auto 关键字自动推导返回类型。这避免了在 Lambda 表达式中手动指定返回类型的需要。

**std::make_unique**:

引入了 std::make_unique,作为 std::make_shared 的对称操作,它简化了对 std::unique_ptr 的创建,避免了不必要的 new 运算符。

**decltype(auto)**:

引入了 decltype(auto) 作为函数返回类型的推导方式,它可以推导出具有精确类型的返回值,支持返回引用类型的自动推导。

标准库改进

C++14 修复了 C++11 标准库中的一些问题,并改进了对各种常见编译器的支持。标准库中对线程、智能指针、算法等的支持变得更加稳定和高效。

二进制字面量

C++14 引入了二进制字面量(0b 或 0B)的支持,使得表示二进制数更加直观。

**std::exchange**:

新增了 std::exchange 函数,它可以简化交换操作,尤其是当你需要交换一个对象并返回其原值时。

示例代码:C++14 新特性

以下代码展示了 C++14 中的一些关键特性,包括泛型 Lambda、变量模板、decltype(auto)std::make_unique 等。

#include <iostream>#include <vector>#include <memory>#include <algorithm>// 1. 泛型 Lambda 表达式void genericLambda() {    auto sum = [](auto a, auto b) { return a + b; };  // 泛型 Lambda    std::cout << "Sum of 3 and 4.5: " << sum(3, 4.5) << std::endl;}// 2. 变量模板template <typename T>T pi = T(3.14159);void variableTemplate() {    std::cout << "Pi as float: " << pi<float> << std::endl;    std::cout << "Pi as double: " << pi<double> << std::endl;}// 3. Lambda 表达式的返回类型推导void lambdaReturnType() {    auto multiply = [](auto a, auto b) { return a * b; };    std::cout << "Multiply 4 and 5.5: " << multiply(4, 5.5) << std::endl;}// 4. 使用 std::make_uniquevoid makeUnique() {    auto ptr = std::make_unique<int[]>(5);  // 使用 make_unique 创建动态数组    ptr[0] = 10;    std::cout << "First element in unique_ptr array: " << ptr[0] << std::endl;}// 5. 使用 decltype(auto) 推导返回类型int&& returnRvalue() {    int x = 5;    return std::move(x);  // 返回右值引用}void decltypeAuto() {    decltype(auto) result = returnRvalue();    std::cout << "Rvalue returned: " << result << std::endl;}// 6. 使用 std::exchangeint increment(int& x) {    return std::exchange(x, x + 1);  // 将 x 的当前值赋给函数并更新 x}void exchangeExample() {    int value = 10;    int oldValue = increment(value);    std::cout << "Old value: " << oldValue << ", New value: " << value << std::endl;}int main() {    // 泛型 Lambda    genericLambda();    // 变量模板    variableTemplate();    // Lambda 返回类型    lambdaReturnType();    // 使用 make_unique    makeUnique();    // 使用 decltype(auto)    decltypeAuto();    // 使用 std::exchange    exchangeExample();    return 0;}

代码解释:

泛型 Lambda 表达式

通过 auto 来声明 Lambda 表达式的参数类型,使得 Lambda 可以接受任意类型的参数。这使得 Lambda 表达式更加灵活,可以应用于多种不同的类型。

变量模板

pi 是一个模板变量,它接受一个类型参数 T,并为每个类型提供不同的常量值。在 variableTemplate() 中,演示了如何使用模板变量来获取 pi 的不同类型值。

Lambda 返回类型推导

使用 auto 关键字,Lambda 表达式会自动推导返回类型。在 lambdaReturnType() 中,返回类型是乘积结果的类型,auto 会自动推导出其正确类型。

**std::make_unique**:

std::make_unique 用于创建 std::unique_ptr,这是一个智能指针,用于管理动态分配的内存。std::make_unique 是 C++14 引入的,它比直接使用 new 更加安全和方便。

**decltype(auto)**:

decltype(auto) 用于推导函数的返回类型,并且支持返回值是引用的情况。在 decltypeAuto() 中,returnRvalue() 返回一个右值引用,通过 decltype(auto) 可以正确地推导出返回类型。

**std::exchange**:

std::exchange 是 C++14 引入的一个小工具,它用于交换一个变量的值并返回旧值。在 exchangeExample() 中,std::exchange 用于交换 value 的值并返回交换前的值。

运行输出:

Sum of 3 and 4.5: 7.5Pi as float: 3.14159Pi as double: 3.14159Multiply 4 and 5.5: 22First element in unique_ptr array: 10Rvalue returned: 5Old value: 10, New value: 11

C++14 的优势:

增强的类型推导:通过 autodecltype(auto)、泛型 Lambda 表达式等新特性,C++14 提供了更加灵活和精简的编程体验。更强大的 Lambda 表达式:C++14 使得 Lambda 表达式支持更复杂的类型推导和捕获方式,提升了函数式编程的能力。内存管理优化std::make_unique 提高了内存管理的安全性和效率,避免了直接使用 new 时可能出现的资源泄漏问题。简化的交换操作std::exchange 使得交换操作更加简洁,尤其是在需要交换并返回原值的场景中。

C++14 的局限性:

更新较小:相比 C++11,C++14 的新特性较少,更多的是对 C++11 特性的增强和补充。因此,C++14 的使用场景更多是在已有代码的优化和小修小补上。编译器支持:尽管大部分现代编译器支持 C++14,但早期的编译器可能对一些新特性的支持不完全,开发者在使用这些特性时需要确认编译器的兼容性。

总结:

C++14 是 C++ 语言的一个小版本更新,主要通过增强和扩展 C++11 中的特性来提升语言的灵活性、可用性和安全性。它引入了泛型 Lambda、变量模板、std::make_unique 等重要特性,并修复了 C++11 中的一些边界问题。C++14 对于已经使用 C++11 的开发者来说是一个重要的改进,但它的变化相对较小,不会像 C++11 那样对整个语言体系造成颠覆性的影响。

8. C++ 2017: C++17

重要更新: 结构化绑定声明:允许通过 auto [x, y] = pair 等语法,直接解构元组或结构体。**std::filesystem**:引入文件系统库,提供跨平台的文件系统操作接口。if 和 switch 初始化:允许在 if 或 switch 语句中直接初始化变量。并行算法:STL 中的算法库支持并行执行,如并行排序。**std::optional**:提供了一个容器,可以包含一个值或为空,用于避免空指针的使用。**std::variant**:实现了类似于联合体的类型,但比 C 的 union 更安全和灵活。**改进的 std::any**:增强了类型安全的通用容器,允许存储任意类型。

C++17(也被称为C++ 2017)是C++编程语言的一个重要版本,它在C++11和C++14的基础上进行了许多改进,增强了语言特性、库功能以及编译器支持。C++17的主要亮点包括:

1. 结构化绑定声明 (Structured Bindings)

C++17 引入了结构化绑定,允许你将一个结构或元组拆分为多个变量,从而让代码更加简洁易读。

示例:
#include <tuple>#include <iostream>std::tuple<int, double, std::string> getData() {    return {1, 3.14, "Hello, C++17!"};}int main() {    auto [x, y, z] = getData();  // 结构化绑定    std::cout << x << ", " << y << ", " << z << std::endl;    return 0;}

输出:

1, 3.14, Hello, C++17!

2. if/else语句中的初始化语句 (If/else with initialization)

C++17允许在ifelse语句中进行变量初始化,避免了冗余的变量声明。

示例:
#include <iostream>int main() {    if (int x = 10; x > 5) {        std::cout << "x is greater than 5" << std::endl;    } else {        std::cout << "x is not greater than 5" << std::endl;    }    return 0;}

输出:

x is greater than 5

注意:x只在ifelse的作用域内有效。

3. std::optional

std::optional 是一个模板类,用来表示一个可能为空的值。它可以用来避免使用空指针或特殊值来表示无效数据。

示例:
#include <iostream>#include <optional>std::optional<int> findValue(bool found) {    if (found) {        return 42;    } else {        return std::nullopt;  // 返回空值    }}int main() {    auto value = findValue(true);    if (value) {        std::cout << "Found value: " << *value << std::endl;    } else {        std::cout << "Value not found" << std::endl;    }    return 0;}

输出:

Found value: 42

4. std::string_view

std::string_view是一个轻量级的字符串视图,避免了复制字符串数据,提供了对字符串的只读访问。

示例:
#include <iostream>#include <string_view>void printString(std::string_view str) {    std::cout << str << std::endl;}int main() {    std::string str = "Hello, C++17!";    printString(str);  // 不会复制数据    return 0;}

输出:

Hello, C++17!

5. std::filesystem

C++17加入了对文件系统操作的标准库支持,std::filesystem使得处理文件和目录变得更加方便。

示例:

<iostream> - C++ Reference

#include <iostream>#include <filesystem>namespace fs = std::filesystem;int main() {    fs::path p = "example.txt";    if (fs::exists(p)) {        std::cout << p << " exists!" << std::endl;    } else {        std::cout << p << " does not exist." << std::endl;    }    return 0;}

输出:

example.txt does not exist.

6. 并行算法 (Parallel Algorithms)

C++17添加了对并行执行算法的支持,例如使用 std::for_each 和其他标准算法的并行执行。

示例:
#include <iostream>#include <vector>#include <algorithm>#include <execution>int main() {    std::vector<int> data = {1, 2, 3, 4, 5, 6, 7, 8, 9};    std::for_each(std::execution::par, data.begin(), data.end(), [](int& x) {        x *= 2;    });    for (int x : data) {        std::cout << x << " ";    }    return 0;}

输出:

2 4 6 8 10 12 14 16 18 

(注意:并行执行可能因环境不同而产生不同的输出顺序)

7. 内联变量 (Inline Variables)

C++17引入了内联变量,解决了头文件中静态变量带来的链接问题。

示例:
#include <iostream>inline int x = 42;  // 内联变量int main() {    std::cout << x << std::endl;    return 0;}

8. 改进的constexpr

C++17扩展了constexpr的功能,允许在编译时执行更多的操作,比如动态分配内存和使用if语句。

示例:
#include <iostream>constexpr int factorial(int n) {    return (n == 0) ? 1 : n * factorial(n - 1);}int main() {    std::cout << "Factorial of 5: " << factorial(5) << std::endl;    return 0;}

输出:

Factorial of 5: 120

总结

C++17引入了许多新特性,极大提高了语言的表达力和编程效率,尤其是在简化代码、提高性能和增加灵活性方面。对于现代C++开发者来说,熟练掌握这些特性将大大提升开发体验和代码质量。

9. C++ 2020: C++20

重大的新特性: 模块(Modules):引入了模块化的支持,替代传统的头文件和源文件方式,减少编译时间。协程(Coroutines):支持异步编程,简化了异步函数的编写。概念(Concepts):引入了模板约束,使得模板编程更加灵活和易于理解。范围(Ranges):增强了容器操作的灵活性和简洁性,提供了更强大的算法支持。**std::format**:提供了类似 Python 中的格式化字符串功能,简化了输出。**consteval 和 constinit**:新关键字,用于常量表达式和常量初始化的严格控制。**改进的 constexpr**:支持更多的编译时功能,包括动态内存分配。

C++20 是 C++ 标准的一个重要更新,它在语言特性、库功能、并发支持等方面进行了大量的扩展和增强。C++20 对语言进行了重要的现代化,使得 C++ 更加高效、简洁、易用。以下是 C++20 中的一些主要特性及其代码示例:

1. 概念 (Concepts)

概念是 C++20 的一项新特性,用来约束模板类型。它允许我们更精确地控制模板参数类型,提供编译时检查和更好的错误信息。

示例:
#include <iostream>#include <concepts>template <typename T>concept Incrementable = requires(T a) { ++a; a++; };template <Incrementable T>T increment(T x) {    return ++x;}int main() {    int a = 5;    std::cout << increment(a) << std::endl;  // 正常工作    // std::string s = "Hello";    // std::cout << increment(s) << std::endl; // 编译错误,因为 std::string 不符合 Incrementable 概念    return 0;}

输出:

6

2. 范围 (Ranges)

C++20 引入了 std::ranges,为标准库中的容器和算法提供了更加一致和方便的操作方法,支持通过管道操作符(|)组合算法。

示例:
#include <iostream>#include <vector>#include <ranges>int main() {    std::vector<int> nums = {1, 2, 3, 4, 5};    // 使用管道操作符对容器进行操作    auto result = nums | std::views::transform([](int x) { return x * 2; })                       | std::views::filter([](int x) { return x > 5; });    for (int val : result) {        std::cout << val << " ";    }    return 0;}

输出:

6 8 10

3. 协程 (Coroutines)

C++20 引入了协程支持,使得编写异步代码更加简洁。协程允许暂停和恢复函数的执行,适用于处理 I/O 操作或其他需要异步操作的场景。

示例:
#include <iostream>#include <coroutine>struct Task {    struct promise_type;    using handle_type = std::coroutine_handle<promise_type>;    struct promise_type {        Task get_return_object() { return Task{handle_type::from_promise(*this)}; }        std::suspend_always initial_suspend() { return {}; }        std::suspend_always final_suspend() noexcept { return {}; }        void unhandled_exception() { std::exit(1); }        void return_void() {}    };    handle_type coro;    Task(handle_type h) : coro(h) {}    ~Task() { coro.destroy(); }    void resume() { coro.resume(); }};Task simpleCoroutine() {    std::cout << "Start of coroutine\n";    co_await std::suspend_always{};    std::cout << "End of coroutine\n";}int main() {    auto coro = simpleCoroutine();    coro.resume();  // 启动协程    coro.resume();  // 恢复协程    return 0;}

输出:

Start of coroutineEnd of coroutine

4. 三向比较 (Spaceship Operator <=>)

C++20 引入了“太空船操作符” (<=>),也叫做三向比较操作符,它提供了一种简化的方式来执行比较操作,如 <<===>>=

示例:
#include <iostream>struct Point {    int x, y;    auto operator<=>(const Point&) const = default;  // 默认生成比较操作符};int main() {    Point p1 = {1, 2}, p2 = {2, 3};        if (p1 < p2) {        std::cout << "p1 is less than p2\n";    }    return 0;}

输出:

p1 is less than p2

5. 模块 (Modules)

C++20 引入了模块的概念,这是对头文件的替代。模块可以提高编译速度,避免头文件带来的重复处理和依赖问题。模块支持 import 语句来替代传统的 #include

示例:

假设我们有一个模块 math

// math.cppm - 模块定义文件export module math;export int add(int a, int b) { return a + b; }

然后在主程序中导入该模块:

// main.cppimport math;int main() {    int result = add(3, 4);    std::cout << result << std::endl;  // 输出 7    return 0;}

注意:模块在许多编译器中仍处于实验阶段,需要启用特定的编译器选项。

6. 范围循环 (Range-based for loop with initializer)

C++20 增强了范围 for 循环,允许在循环中初始化变量。

示例:
#include <iostream>#include <vector>int main() {    std::vector<int> nums = {1, 2, 3, 4};    for (auto&& [index, value] : nums) {  // 使用结构化绑定        std::cout << "Value: " << value << std::endl;    }    return 0;}

输出:

Value: 1Value: 2Value: 3Value: 4

7. std::span

std::span 是 C++20 新增的一个轻量级的视图容器,它可以用来表示一个数组的连续区间。它与传统的指针数组相比,更加安全,并支持对数组进行边界检查。

示例:
#include <iostream>#include <span>void printSpan(std::span<int> sp) {    for (auto val : sp) {        std::cout << val << " ";    }}int main() {    int arr[] = {1, 2, 3, 4, 5};    printSpan(arr);  // 使用 std::span 传递数组    return 0;}

输出:

1 2 3 4 5 

8. consteval 和 constinit

C++20 引入了 consteval 和 constinit 关键字:

consteval 用于指定一个函数必须在编译时求值。constinit 用于确保某个变量在初始化时是常量。
示例:
#include <iostream>consteval int square(int n) { return n * n; }int main() {    constexpr int result = square(5);  // 在编译时计算    std::cout << result << std::endl;  // 输出 25    return 0;}

输出:

25

总结

C++20 引入了许多强大的新特性,极大增强了 C++ 的表达能力和编程效率。它使得编写更现代、更安全和更高效的 C++ 代码变得更加容易。例如,概念和协程提高了代码的可读性和可维护性,而模块的引入可以显著提高编译性能。掌握 C++20 的特性将有助于编写更清晰、强大和高效的 C++ 代码。

10. C++ 2023: C++23

新特性和小幅增强: **扩展的 std::ranges**:提供更多的支持与增强,使得 C++ 的标准库更具表达力和功能。 改进的协程支持:协程功能得到进一步加强,增加了更多的灵活性和优化。更好的标准化和规范:提高了 C++ 语言和标准库的易用性和性能。

C++23(正式名称为 C++23)是C++语言的最新标准,作为C++20和C++17之后的下一代标准,C++23在语言特性、库功能和编译器优化等方面引入了一些重要的改进。以下是C++23中的一些新特性和代码示例。

1. 改进的常量表达式(constexpr

C++23扩展了constexpr的功能,允许更多复杂的功能在编译时执行。例如,C++23允许在constexpr函数中使用try-catch语句,这在之前的标准中是无法实现的。

示例:
constexpr int safe_divide(int a, int b) {    if (b == 0) throw std::invalid_argument("Division by zero");    return a / b;}int main() {    constexpr int result = safe_divide(10, 2);  // 编译时执行    return 0;}

2. std::expected

C++23引入了std::expected,它是一个可以用来表示函数调用结果的类型,类似于std::optional,但是它包含了错误信息。这个特性非常适合替代try-catch块来进行错误处理,尤其是在函数返回时希望包含更多的错误信息时。

示例:
#include <expected>#include <iostream>std::expected<int, std::string> divide(int a, int b) {    if (b == 0) {        return std::unexpected("Division by zero");    }    return a / b;}int main() {    auto result = divide(10, 0);    if (result) {        std::cout << "Result: " << *result << std::endl;    } else {        std::cout << "Error: " << result.error() << std::endl;    }    return 0;}

3. 范围(Ranges)库增强

C++20引入了范围(Ranges)库,C++23在此基础上进行了增强。新增了更丰富的算法和视图,使得在进行集合操作时,代码更加简洁且易于理解。

示例:
#include <ranges>#include <vector>#include <iostream>int main() {    std::vector<int> v = {1, 2, 3, 4, 5};    // 使用ranges库处理集合    auto result = v | std::views::transform([](int n) { return n * n; })                    | std::views::filter([](int n) { return n > 10; });    for (int i : result) {        std::cout << i << " ";    }    return 0;}

4. std::format 改进

C++20引入了 std::format 来格式化字符串,C++23对其进行了进一步改进。新增了更多的格式化选项,以及对各种类型的支持。

示例:
#include <format>#include <iostream>int main() {    int age = 25;    std::string name = "Alice";    std::string formatted = std::format("Name: {}, Age: {}", name, age);    std::cout << formatted << std::endl;    return 0;}

5. explicit 改进

C++23扩展了explicit关键字,可以用于更加灵活的构造函数,使其适应更复杂的类型转换需求。

示例:
struct A {    explicit A(int x) {}  // 显式构造函数};struct B {    explicit B(A a) {}  // 显式构造函数};int main() {    A a(1);    B b(a);  // 需要显示构造A对象的参数    return 0;}

6. std::span 支持的改进

std::span 是C++20中引入的用于表示数组片段的类,C++23对其进行了扩展,支持了更多的功能。

示例:
#include <span>#include <iostream>void print_span(std::span<int> s) {    for (auto elem : s) {        std::cout << elem << " ";    }}int main() {    int arr[] = {1, 2, 3, 4, 5};    std::span<int> sp(arr, 3);  // 只传递数组的前3个元素    print_span(sp);    return 0;}

7. 新的属性([[likely]] 和 [[unlikely]]

C++23引入了 [[likely]] 和 [[unlikely]] 属性,用于给编译器提供分支预测的提示,帮助优化代码。

示例:
#include <iostream>int main() {    bool condition = true;    if ([[likely]] condition) {        std::cout << "Condition is likely true" << std::endl;    } else {        std::cout << "Condition is unlikely true" << std::endl;    }    return 0;}

总结

C++23增强了语言的表达能力和效率,提供了更多的编程便利性,尤其在常量表达式、错误处理、范围操作、字符串格式化和编译时优化方面有显著的提升。这些特性使得C++更加现代化,代码更加简洁易懂,同时也带来了更高效的执行性能。

这些新特性和API增强为开发者提供了更加灵活和强大的工具,可以让代码更加高效、易维护并且更具可读性。



点击全文阅读


本文链接:http://zhangshiyu.com/post/197507.html

<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1