C++ 的发展
目录
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++11 | 2011年 |
| C++14 | 2014年 |
| C++17 | 2017年 |
| C++20 | 2020年 |
| C++23 | 2023年 |
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_ptr、std::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::format、std::ranges、std::calendar等。
- C++20 为 C++ 带来了大量的现代化特性,并进一步提升了语言的表达能力、性能和并发编程的支持。
8. C++23(2023年)
- 2023年:C++23 发布,虽然其变化相较于 C++20 比较平稳,但仍然包含了一些重要的改进和修复:
- 新的标准库功能:例如,
std::expected、std::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**:定义了一个包含length、breadth和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;// 基类A
class A {
public:A() { cout << "Class A constructor" << endl; }void showA() { cout << "Class A" << endl; }
};// 基类B
class B {
public:B() { cout << "Class B constructor" << endl; }void showB() { cout << "Class B" << endl; }
};// 基类C,虚继承A
class C : virtual public A {
public:C() { cout << "Class C constructor" << endl; }void showC() { cout << "Class C" << endl; }
};// 派生类D,虚继承A和B
class D : public C, public B {
public:D() { cout << "Class D constructor" << endl; }void showD() { cout << "Class D" << endl; }
};int main() {// 创建派生类对象DD d;d.showA(); // 来自基类Ad.showB(); // 来自基类Bd.showC(); // 来自基类Cd.showD(); // 来自派生类Dreturn 0;
}
代码讲解:
- 类 A 和 B:
A和B是两个基类,都有自己的构造函数和成员函数。A有一个showA()函数,B有一个showB()函数。 - 类 C:
C类继承了A类,并使用virtual关键字进行 虚继承。这样,在C的子类中,如果有多个继承自A的路径,它们会共享同一个A类副本,避免了重复数据。 - 类 D:
D类从C和B继承,并且通过虚继承机制共享了A类的副本。 - 输出:
- 当
D类的对象被创建时,首先调用A、B和C的构造函数,再调用D的构造函数。 showA()、showB()和showC()分别调用了从基类继承的成员函数。
- 当
运行输出:
Class A constructor
Class B constructor
Class C constructor
Class D constructor
Class A
Class B
Class C
Class D
解释:
- 虚继承:
C类通过virtual public A虚继承了A类,保证了通过D类的继承关系,A类只有一份副本。即使D类是通过B和C两个路径继承A,A类也只会被构造一次。 - 多重继承:
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是一个类型参数,可以是任何数据类型(如int、double等),当调用模板函数时,编译器会根据传入的参数类型推导出T的具体类型。
-
**类模板
Box**:Box是一个类模板,它有一个类型为T的成员变量value。- 构造函数接受一个
T类型的参数来初始化value,并提供了getValue和setValue方法来访问和修改value。
运行输出:
Max of x and y: 20
Max of a and b: 3.14
Box contains: 100
Updated Box contains: 200
Box 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(标准模板库):引入了标准模板库,包括
vector、list、map、set等容器,及算法(如排序、查找等)。map - C++ Reference set - C++ Reference - 命名空间(namespace):为了避免名称冲突,引入了命名空间。
- 异常处理:引入了
try、catch、throw异常处理机制。 - RTTI(运行时类型信息):引入了
typeid和dynamic_cast,允许运行时识别对象的类型。
- STL(标准模板库):引入了标准模板库,包括
C++98 是 C++ 语言的第一个国际标准,正式由 ISO(国际标准化组织)在 1998 年发布。C++98 语言标准继承了 C++ 3.0 的核心特性,并在此基础上进行了多个重要的改进和规范化。这个版本的 C++ 为标准库(STL)提供了规范,并开始支持更多的现代编程特性。
主要特性:
-
模板:
- C++98 中的模板特性得到了进一步的增强,支持函数模板和类模板,并且模板的使用变得更加广泛。模板参数可以是类、函数、指针等类型。
-
标准模板库(STL)
sort - C++ Reference
-
异常处理:
- C++98 提供了标准化的异常处理机制,使用
try,catch,throw语句来处理运行时错误。
- C++98 提供了标准化的异常处理机制,使用
-
命名空间:
- C++98 引入了 命名空间(
namespace),用于避免名称冲突,尤其是在大型项目中。
- C++98 引入了 命名空间(
-
虚函数与多态:
- C++98 继续强化了面向对象编程的支持,特别是对 虚函数 和 多态 的使用。
-
const 和引用:
- C++98 对
const关键字和引用进行了严格的规范,使得编程更加安全。
- C++98 对
-
函数指针和类型转换:
- 提供了对 函数指针 和 类型转换(如
static_cast,dynamic_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: 20
Sorted vector: 1 1 2 3 3 4 5 5 5 6 9
Caught exception: Index out of range!
代码解释:
- **模板
getMax**:通过模板,可以在运行时自动确定T的类型,支持不同的数据类型(如int、double等)。在本例中,它比较了两个整数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++98 标准库中的一些小问题。例如,修复了
-
修复了常见的编译器问题:
- 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>::type
printType(const T& value) {std::cout << "Non-integer value: " << value << std::endl;
}template <typename T>
typename std::enable_if<std::is_integral<T>::value, void>::type
printType(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)会被调用。
-
运行输出:
123
const value: 456
Integer value: 123
Non-integer value: 3.14
C++03 与 C++98 的局限性:
- 没有新的语言特性:C++03 仅仅是 C++98 的修正版本,没有引入新的语言特性。开发者并未从中获得像 C++11、C++14、C++17 那样的重大进展。
- 标准库的改进有限:虽然 C++03 修复了一些标准库的问题,但与后来的 C++ 标准相比,它的功能仍显得较为简单。
- 没有现代化工具:如
auto、nullptr、范围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_ptr、std::shared_ptr、std::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>库使得多线程编程变得更加容易和高效。
- C++11 引入了原生的线程支持,
-
类型别名(
using):using关键字可以用来为类型定义别名,取代了传统的typedef,语法更加简洁。
-
强类型枚举(
enum class):- 引入了强类型枚举
enum class,避免了传统枚举可能产生的隐式转换和命名冲突问题。
- 引入了强类型枚举
-
**新标准库:
std::chrono**:- C++11 引入了用于处理时间和日期的新标准库
std::chrono,使得处理时间变得更加直观和精确。
- C++11 引入了用于处理时间和日期的新标准库
示例代码:C++11 特性
下面的代码示例展示了 C++11 的一些关键特性。
#include <iostream>
#include <vector>
#include <algorithm>
#include <thread>
#include <functional>// 1. 自动类型推导
void autoExample() {auto x = 10; // 编译器自动推导类型为 intauto y = 3.14; // 编译器自动推导类型为 doublestd::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循环来遍历容器。这个语法简洁、直观,避免了显式的迭代器操作。
- 使用 C++11 引入的范围
-
Lambda 表达式:
- 使用
std::for_each算法与 lambda 表达式结合,计算容器中所有元素的总和。lambda 表达式[&sum](int num) { sum += num; }捕获外部变量sum并对容器中的每个元素执行加法操作。
- 使用
-
右值引用与移动语义:
- 在
moveExample中,通过std::move实现了对象a的移动,将其资源转移给对象b,触发了移动构造函数而不是拷贝构造函数。
- 在
-
线程支持:
- 使用 C++11 的
<thread>库创建和启动一个线程,并且通过join()等待线程执行完成。std::thread简化了多线程编程。
- 使用 C++11 的
运行输出:
x: 10, y: 3.14
Doubled values: 2 4 6 8 10
Sum of elements: 15
Move Constructor
Hello 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 表达式中手动指定返回类型的需要。
- 在 C++14 中,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)的支持,使得表示二进制数更加直观。
- C++14 引入了二进制字面量(
-
**
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; }; // 泛型 Lambdastd::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_unique
void 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::exchange
int 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() {// 泛型 LambdagenericLambda();// 变量模板variableTemplate();// Lambda 返回类型lambdaReturnType();// 使用 make_uniquemakeUnique();// 使用 decltype(auto)decltypeAuto();// 使用 std::exchangeexchangeExample();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.5
Pi as float: 3.14159
Pi as double: 3.14159
Multiply 4 and 5.5: 22
First element in unique_ptr array: 10
Rvalue returned: 5
Old value: 10, New value: 11
C++14 的优势:
- 增强的类型推导:通过
auto、decltype(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允许在if或else语句中进行变量初始化,避免了冗余的变量声明。
示例:
#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只在if或else的作用域内有效。
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 coroutine
End 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.cpp
import math;int main() {int result = add(3, 4);std::cout << result << std::endl; // 输出 7return 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: 1
Value: 2
Value: 3
Value: 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; // 输出 25return 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增强为开发者提供了更加灵活和强大的工具,可以让代码更加高效、易维护并且更具可读性。
相关文章:
C++ 的发展
目录 C 的发展总结:编辑 1. C 的早期发展(1979-1985) 2. C 标准化过程(1985-1998) 3. C 标准演化(2003-2011) 4. C11(2011年) 5. C14(2014年…...
RabbitMQ 高级特性——延迟队列
文章目录 前言延迟队列延迟队列的概念TTL 死信队列模拟延迟队列设置队列的 TTL设置消息的 TTL 延迟队列插件安装并且启动插件服务使用插件实现延迟功能 前言 前面我们学习了 TTL 和死信队列,当队列中的消息达到了过期时间之后,那么这个消息就会被死信交…...
EAC(Estimate at Completion)和ETC(Estimate to Complete)
EAC 预计完工成本ETC 预计尚需成本Estimate at CompletionEstimate to Complete完成预估完工时尚需成本估算 EAC ETC ACETC EAC – AC 预测项目总成本,包含了到目前为止实际发生的成本(AC)和预计将发生的成本。如果EAC大于BAC…...
【React】状态管理之Zustand
🌈个人主页: 鑫宝Code 🔥热门专栏: 闲话杂谈| 炫酷HTML | JavaScript基础 💫个人格言: "如无必要,勿增实体" 文章目录 状态管理之Zustand引言1. Zustand 的核心特点1.1 简单直观的 API1.2 无需 Provi…...
Vue3打包自动生成版本JSON文件,添加系统版本检查,实现系统自动更新提示
实现该功能一共有三步。废话不多说,直接上代码!!! 第一步:打包时自动生成版本信息的js文件,versionUpdate.js import fs from fs; import path from path; import { ElMessageBox } from element-plus; i…...
海量数据有限内存系列问题解决方案
1. 排序问题 有限数据充足内存:内存中有十万整数,对所有数据进行排序。 内部排序即可 单节点海量数据有限内存:某台机器有一个文件,文件中包含六十亿整数,一个整数一行,可用内存1G,对所有数据…...
FFmpeg 4.3 音视频-多路H265监控录放C++开发十四,总结编码过程,从摄像头获得数据后,转成AVFrame,然后再次转成AVPacket,
也就是将摄像头采集到的YUV 的数据换成 AVFrame,然后再次转成 AVPacket,那么这AVPakcet数据要怎么办呢?分为三种情况: 一种是将AVPacket存储成h264文件,由于h264编码器在将avframe变成avpacket的时候就是按照h264的格…...
内容占位符:Kinetic Loader HTML+CSS 使用CSS制作三角形原理
内容占位符 前言 随着我们对HTML和CSS3的学习逐渐深入,相信大家都已经掌握了网页制作的基础知识,包括如何使用HTML标记构建网页结构,以及如何运用CSS样式美化页面。为了进一步巩固和熟练这些技能,今天我们一起来完成一个有趣且实…...
麒麟nginx配置
一、配置负载均衡 配置麒麟的yum源 vim /etc/yum.repos.d/kylin_aarch64.repo Copy 删除原来内容,写入如下yum源 [ks10-adv-os] name Kylin Linux Advanced Server 10 - Os baseurl http://update.cs2c.com.cn:8080/NS/V10/V10SP2/os/adv/lic/base/aarch64/ …...
如何在 Ubuntu 上安装 Emby 媒体服务器
Emby 是一个开源的媒体服务器解决方案,它能让你整理、流媒体播放和分享你的个人媒体收藏,包括电影、音乐、电视节目和照片。Emby 帮你集中多媒体内容,让你无论在家还是在外都能轻松访问。它还支持转码,让你能够播放各种格式的内容…...
Mac上详细配置java开发环境和软件(更新中)
文章目录 概要JDK的配置JDK下载安装配置JDK环境变量文件 Idea的安装Mysql安装和配置Navicat Premium16.1安装安装Vscode安装和配置Maven配置本地仓库配置阿里云私服Idea集成Maven 概要 这里使用的是M3型片 14.6版本的Mac 用到的资源放在网盘 链接: https://pan.baidu.com/s/17…...
jmeter常用配置元件介绍总结之定时器
系列文章目录 安装jmeter jmeter常用配置元件介绍总结之定时器 5.定时器5.1.固定定时器5.2.统一随机定时器5.3.Precise Throughput Timer5.4.Constant Throughput Timer5.5.Synchronizing Timer5.6.泊松随机定时器5.7.高斯随机定时器 5.定时器 5.1.固定定时器 固定定时器Cons…...
Spring——提前编译
提前编译:AOT AOT概述 JIT与AOT的区别 JIT和AOT 这个名词是指两种不同的编译方式,这两种编译方式的主要区别在于是否在“运行时”进行编译 (1)JIT, Just-in-time,动态(即时)编译,边运行边编译࿱…...
乐理的学习(音程)
二度,三度,六度,七度的大n度都是直接的音名到音名,如#A到#G的,这样为大n度 而这个基础上向内收,收半音为小n度,在小n度再收,为减n度 在大n度的基础上再向外扩半音,为增…...
【网络】数据链路层协议——以太网,ARP协议
> 作者:დ旧言~ > 座右铭:松树千年终是朽,槿花一日自为荣。 > 目标:了解什么是以太网协议和ARP协议。 > 毒鸡汤:有些事情,总是不明白,所以我不会坚持。早安! > 专栏选自…...
Linux分区、挂载、配额、逻辑卷、RAID、系统综合状态查看
分区与挂载 fdisk fdisk 命令是一个用于磁盘分区管理的命令行工具,可以用来创建、删除、调整分区等操作。常用的 fdisk 命令选项包括: fdisk -l:列出系统中的所有磁盘分区信息。 fdisk /dev/sdX:打开指定磁盘进行分区操作。 n&…...
3D Gaussian Splatting 代码层理解之Part1
2023 年初,来自蔚蓝海岸大学和 马克斯普朗克学会的作者发表了一篇题为“用于实时现场渲染的 3D 高斯泼溅”的论文。该论文提出了实时神经渲染的重大进步,超越了NeRF等以前方法的实用性。高斯泼溅不仅减少了延迟,而且达到或超过了 NeRF 的渲染质量,在神经渲染领域掀起了一场…...
Qt小知识-Q_GLOBAL_STATIC
你还在为创建全局静态对象烦恼嘛,它来了!它来了! qt5提供了两个宏定义Q_GLOBAL_STATIC和Q_GLOBAL_STATIC_WITH_ARGS来实现。可以创建一个全局静态对象,对象在第一次使用时初始化自身,这意味着它不会增加应用程序或库的…...
【SpringBoot】使用过滤器进行XSS防御
在Spring Boot中,我们可以使用注解的方式来进行XSS防御。注解是一种轻量级的防御手段,它可以在方法或字段级别对输入进行校验,从而防止XSS攻击。 而想对全局的请求都进行XSS防御可以使用servlet中的过滤器或者spring mvc中的拦截器ÿ…...
创建vue插件,发布npm
开发步骤:1.创建一个vue项目,2.开发一个组件。 3.注册成插件。 4.vite和package.json配置。5.发布到npm 1.创建一个vue项目 npm create vuelatest 生成了vue项目之后,得到了以下结构。 在src下创建个plugins目录。用于存放开发的…...
国防科技大学计算机基础课程笔记02信息编码
1.机内码和国标码 国标码就是我们非常熟悉的这个GB2312,但是因为都是16进制,因此这个了16进制的数据既可以翻译成为这个机器码,也可以翻译成为这个国标码,所以这个时候很容易会出现这个歧义的情况; 因此,我们的这个国…...
UE5 学习系列(三)创建和移动物体
这篇博客是该系列的第三篇,是在之前两篇博客的基础上展开,主要介绍如何在操作界面中创建和拖动物体,这篇博客跟随的视频链接如下: B 站视频:s03-创建和移动物体 如果你不打算开之前的博客并且对UE5 比较熟的话按照以…...
蓝桥杯 2024 15届国赛 A组 儿童节快乐
P10576 [蓝桥杯 2024 国 A] 儿童节快乐 题目描述 五彩斑斓的气球在蓝天下悠然飘荡,轻快的音乐在耳边持续回荡,小朋友们手牵着手一同畅快欢笑。在这样一片安乐祥和的氛围下,六一来了。 今天是六一儿童节,小蓝老师为了让大家在节…...
C# 类和继承(抽象类)
抽象类 抽象类是指设计为被继承的类。抽象类只能被用作其他类的基类。 不能创建抽象类的实例。抽象类使用abstract修饰符声明。 抽象类可以包含抽象成员或普通的非抽象成员。抽象类的成员可以是抽象成员和普通带 实现的成员的任意组合。抽象类自己可以派生自另一个抽象类。例…...
ardupilot 开发环境eclipse 中import 缺少C++
目录 文章目录 目录摘要1.修复过程摘要 本节主要解决ardupilot 开发环境eclipse 中import 缺少C++,无法导入ardupilot代码,会引起查看不方便的问题。如下图所示 1.修复过程 0.安装ubuntu 软件中自带的eclipse 1.打开eclipse—Help—install new software 2.在 Work with中…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...
Pinocchio 库详解及其在足式机器人上的应用
Pinocchio 库详解及其在足式机器人上的应用 Pinocchio (Pinocchio is not only a nose) 是一个开源的 C 库,专门用于快速计算机器人模型的正向运动学、逆向运动学、雅可比矩阵、动力学和动力学导数。它主要关注效率和准确性,并提供了一个通用的框架&…...
mac 安装homebrew (nvm 及git)
mac 安装nvm 及git 万恶之源 mac 安装这些东西离不开Xcode。及homebrew 一、先说安装git步骤 通用: 方法一:使用 Homebrew 安装 Git(推荐) 步骤如下:打开终端(Terminal.app) 1.安装 Homebrew…...
C++ 设计模式 《小明的奶茶加料风波》
👨🎓 模式名称:装饰器模式(Decorator Pattern) 👦 小明最近上线了校园奶茶配送功能,业务火爆,大家都在加料: 有的同学要加波霸 🟤,有的要加椰果…...
从面试角度回答Android中ContentProvider启动原理
Android中ContentProvider原理的面试角度解析,分为已启动和未启动两种场景: 一、ContentProvider已启动的情况 1. 核心流程 触发条件:当其他组件(如Activity、Service)通过ContentR…...
