自 C++11 以来,现代 C++ 经历了一系列重大更新,每次更新都带来旨在让语言更高效、更可读、更易维护的新特性和增强。以下是自 C++11 以来各版本引入的主要特性概览,并附有对其使用情况的点评:
C++11
C++11 标志着 C++ 语言的重大演进,引入了多个强大特性,使 C++ 编程更加现代化和简化。以下是其中最具影响力的特性及说明其用法的示例:
1. auto 类型推导
auto关键字允许编译器根据变量的初始值自动推导其类型。
auto x = 42; // int
auto y = 3.14; // double
auto s = "hello"; // const char*
2.Lambda 表达式
Lambda 提供了一种在代码中直接定义匿名函数的简洁方式。
auto add = [](int a, int b) { return a + b; };
int result = add(3, 4); // result is 7
3.基于范围的 for 循环
简化了对数组、vector 及其他容器等集合的遍历。
std::vector<int> numbers = {1, 2, 3, 4, 5};
for (int n : numbers) {
std::cout << n << " ";
}
4.智能指针
引入std::unique_ptr和std::shared_ptr来自动管理动态内存,防止内存泄漏。
std::unique_ptr<int> ptr(new int(10));
// No need to delete ptr manually; it will be deleted when it goes out of scope
5.移动语义
移动语义通过允许资源转移而非拷贝来优化性能。
std::vector<int> makeVector() {
std::vector<int> v = {1, 2, 3};
return v; // Moves v rather than copying
}
std::vector<int> v = makeVector(); // Efficient move
6.nullptr
用NULL替代nullptr,以更安全地表示空指针。
int* p = nullptr; // p is a null pointer
7.constexpr
支持编译期常量表达式,通过在编译期执行计算来提升性能。
constexpr int square(int x) {
return x * x;
}
int arr[square(5)]; // Creates an array of size 25
8.std::thread
提供创建和管理线程的标准方式,支持并发编程。
#include <thread>
#include <iostream>
void hello() {
std::cout << "Hello from thread!" << std::endl;
}
int main() {
std::thread t(hello);
t.join(); // Wait for thread to finish
return 0;
}
9.可变参数模板
支持参数数量可变的模板,使模板编程更加灵活。
template<typename... Args>
void print(Args... args) {
(std::cout << ... << args) << std::endl; // Fold expression (C++17)
}
print(1, 2, "three", 4.0);
10.统一初始化
为变量和容器的初始化提供一致的语法。
int arr[] = {1, 2, 3};
std::vector<int> v = {1, 2, 3, 4, 5};
struct Point { int x, y; };
Point p = {1, 2};
C++14
C++14 在 C++11 的基础上,引入了若干重要增强,以提升代码的可读性、灵活性和性能。以下是主要特性及示例:
1. 泛型 lambda
C++14 允许在 lambda 参数列表中使用auto,使 lambda 更灵活、更易于与泛型代码配合使用。
示例:
auto add = [](auto a, auto b) { return a + b; };
std::cout << add(1, 2) << std::endl; // Output: 3
std::cout << add(1.5, 2.3) << std::endl; // Output: 3.8
2. 变量模板
变量模板允许为变量(而不仅是函数或类)定义模板。
示例:
template<typename T>
constexpr T pi = T(3.1415926535897932385L);
std::cout << pi<double> << std::endl; // Output: 3.14159
std::cout << pi<float> << std::endl; // Output: 3.14159f
3. 返回类型推导
C++14 允许函数使用auto自动推导返回类型。
示例:
auto add(int a, int b) {
return a + b;
}
std::cout << add(1, 2) << std::endl; // Output: 3
4. std::make_unique
这个工具函数简化了std::unique_ptr实例的创建,使代码更可读、更不易出错。
示例:
#include <memory>
auto ptr = std::make_unique<int>(42);
std::cout << *ptr << std::endl; // Output: 42
5. deprecated 属性
[[deprecated]]属性可用于将函数和变量标记为已弃用,在使用它们时产生编译期警告。
示例:
[[deprecated("Use new_function() instead")]]
void old_function() {}
void new_function() {}
int main() {
old_function(); // Warning: 'old_function' is deprecated: Use new_function() instead
new_function();
}
6. 二进制字面量与数字分隔符
C++ 引入了以0b或0B为前缀的二进制字面量,并使用单引号作为数字分隔符,以提高大数字的可读性。
示例:
int binary = 0b1010; // Binary literal
int largeNumber = 1'000'000; // Digit separator
std::cout << binary << std::endl; // Output: 10
std::cout << largeNumber << std::endl; // Output: 1000000
C++17
C++17 带来了大量新特性和增强,使语言更具表达力且更易用。以下是一些主要新增特性的详细说明和示例:
1. std::optional
std::optional是一个工具类型,表示一个可能存在也可能不存在的值。它对于可能不返回值的函数很有用。
示例:
#include <optional>
#include <iostream>
std::optional<int> find_even_number(int num) {
if (num % 2 == 0) return num;
return std::nullopt;
}
int main() {
auto result = find_even_number(4);
if (result) {
std::cout << "Even number: " << *result << "\n";
} else {
std::cout << "Not an even number\n";
}
}
2. std::variant
std::variant是类型安全的联合体,允许变量保存若干指定类型之一。
示例:
#include <variant>
#include <iostream>
int main() {
std::variant<int, float, std::string> my_variant;
my_variant = 10;
std::cout << std::get<int>(my_variant) << "\n";
my_variant = 3.14f;
std::cout << std::get<float>(my_variant) << "\n";
my_variant = "Hello";
std::cout << std::get<std::string>(my_variant) << "\n";
}
3. std::any
std::any是类型安全的容器,可保存任意类型的单个值。当值的类型在编译期未知时,它很有用。
示例:
#include <any>
#include <iostream>
int main() {
std::any my_any;
my_any = 42;
std::cout << std::any_cast<int>(my_any) << "\n";
my_any = std::string("Hello");
std::cout << std::any_cast<std::string>(my_any) << "\n";
}
4. 结构化绑定
结构化绑定允许将类元组对象直接解包到独立的变量中。
示例:
#include <tuple>
#include <iostream>
std::tuple<int, float, std::string> get_data() {
return {1, 2.3f, "test"};
}
int main() {
auto [i, f, s] = get_data();
std::cout << "i: " << i << ", f: " << f << ", s: " << s << "\n";
}
5. if constexpr
if constexpr支持编译期条件编译。
示例:
#include <iostream>
template <typename T>
void print_type_info(T value) {
if constexpr (std::is_integral_v<T>) {
std::cout << "Integral type\n";
} else {
std::cout << "Non-integral type\n";
}
}
int main() {
print_type_info(42);
print_type_info(3.14);
}
6. 折叠表达式
折叠表达式通过为参数包上的操作提供简洁语法,简化了可变参数模板的使用。
示例:
#include <iostream>
template<typename... Args>
auto sum(Args... args) {
return (... + args); // fold expression
}
int main() {
std::cout << "Sum: " << sum(1, 2, 3, 4, 5) << "\n";
}
7. 文件系统库
<filesystem>库提供了对文件系统及其组件执行操作的设施。
示例:
#include <filesystem>
#include <iostream>
int main() {
std::filesystem::path p{"example.txt"};
if (std::filesystem::exists(p)) {
std::cout << p << " exists\n";
} else {
std::cout << p << " does not exist\n";
}
}
这些特性共同增强了 C++ 的能力与灵活性,使编写健壮、现代、高效的代码更加容易。
C++20
C++20 是 C++ 演进中的一个里程碑,带来了一系列增强语言表达力、安全性和性能的强大特性。以下是对主要新增特性及示例的详细介绍:
1. 概念(Concepts)
概念提供了一种对模板参数指定约束的方式,使模板更可读、错误信息更易理解。
#include <concepts>
#include <iostream>
template <typename T>
concept Integral = std::is_integral_v<T>;
template <Integral T>
T add(T a, T b) {
return a + b;
}
int main() {
std::cout << add(3, 4) << '\n'; // Works
// std::cout << add(3.0, 4.0) << '\n'; // Error: double doesn't satisfy Integral
}
2. 范围(Ranges)
Ranges 库引入了处理数据序列的新方式,使代码更可读、更具表达力。
#include <ranges>
#include <vector>
#include <iostream>
int main() {
std::vector<int> v = {1, 2, 3, 4, 5};
auto result = v | std::ranges::views::filter([](int n) { return n % 2 == 0; });
for (int n : result) {
std::cout << n << ' '; // Output: 2 4
}
}
3. 协程
协程使以顺序风格编写异步代码成为可能,简化了并发应用的开发。
#include <coroutine>
#include <iostream>
struct ReturnObject {
struct promise_type {
ReturnObject get_return_object() { return {}; }
std::suspend_never initial_suspend() { return {}; }
std::suspend_never final_suspend() noexcept { return {}; }
void unhandled_exception() {}
void return_void() {}
};
};
ReturnObject foo() {
std::cout << "Hello ";
co_await std::suspend_always{};
std::cout << "World\n";
}
int main() {
auto handle = foo();
handle.resume();
handle.resume();
}
4. 模块
模块提供了组织和导入代码的新方式,可缩短编译时间并增强代码封装性。
// my_module.ixx
export module my_module;
export int add(int a, int b) {
return a + b;
}
// main.cpp
import my_module;
#include <iostream>
int main() {
std::cout << add(3, 4) << '\n'; // Output: 7
}
5. 三路比较(太空船运算符)
三路比较运算符(<=>)简化了比较的实现,并提供了一致的处理方式。
#include <compare>
#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"; // Output
}
}
6. 日历与时区库
该库为处理日期、时间和时区提供了全面的支持。
#include <chrono>
#include <iostream>
int main() {
using namespace std::chrono;
auto now = system_clock::now();
auto today = floor<days>(now);
std::cout << "Today is: " << today.time_since_epoch().count() << " days since epoch\n";
}
C++20 极大地丰富了这门语言,使其在广泛的编程任务中更加现代和强大。这些特性共同提升了 C++ 代码的健壮性、可读性和可维护性。
C++23
C++23 引入了若干强大特性,增强了语言的能力、安全性和易用性。以下是一些最重要的新增特性的详细介绍:
1. std::expected
std::expected是用于错误处理的新工具,类似于std::optional,但内置了错误状态管理。
示例:
#include <iostream>
#include <expected>
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 << "Error: " << result.error() << '\n';
} else {
std::cout << "Result: " << *result << '\n';
}
}
2. std::mdspan
std::mdspan是多维数组视图,提供了一种描述数据在内存中形状和布局的方式。
示例:
#include <iostream>
#include <mdspan>
int main() {
int data[6] = {1, 2, 3, 4, 5, 6};
std::mdspan<int, std::extents<2, 3>> mdspan(data);
for (int i = 0; i < 2; ++i) {
for (int j = 0; j < 3; ++j) {
std::cout << mdspan(i, j) << ' ';
}
std::cout << '\n';
}
}
3. 反射(实验性)
C++23 引入了实验性的反射能力,允许对类型及其属性进行编译期内省。
示例:
#include <iostream>
#include <experimental/reflect>
struct MyStruct {
int a;
double b;
void foo() {}
};
int main() {
auto type = reflexpr(MyStruct);
for (auto member : type.get_data_members()) {
std::cout << "Member name: " << member.get_name() << '\n';
}
}
4. if consteval
if consteval语句允许代码检查自身是否正在编译期求值。
示例:
#include <iostream>
constexpr int factorial(int n) {
if consteval {
if (n < 0) throw "Negative input!";
}
return n <= 1 ? 1 : n * factorial(n - 1);
}
int main() {
std::cout << factorial(5) << '\n'; // OK
// std::cout << factorial(-1) << '\n'; // Compile-time error
}
5.[[assume]] 属性
[[assume]]属性允许开发者向优化器提供假设,通过告知编译器不变量来提升性能。
示例:
#include <iostream>
int main() {
int x = 5;
[[assume(x > 0)]];
std::cout << "x is positive.\n";
}
这些特性显著增强了 C++ 的表达力、安全性和性能,使其依然是现代软件开发的稳健选择。不过,其中您已经用过多少了呢?
