C++: 从 C++11 到 C++23 的演进之路

C++ 从 2011 年开始进入了快速发展的时代,每三年一个新标准,带来了大量现代特性。本文将梳理 C++11 到 C++23 的主要特性和常用特性。

C++11

Core FeatureLibraryConcurrency

C++14

Core FeatureLibraryConcurrency

C++17

Core FeatureLibraryConcurrency

C++20

The BigCore FeatureLibraryConcurrency

C++23

Core FeatureLibraryConcurrency
  • -

C++11:现代 C++ 的开端

C++11 是 C++ 历史上最重要的标准之一,它彻底改变了 C++ 的编程方式,被称为"现代 C++"的起点。

自动类型推导(auto)

auto x = 42;                        // int
auto y = 3.14;                      // double
auto z = std::vector<int>{1, 2, 3}; // std::vector<int>

// 范围 for 循环
std::vector<int> vec = {1, 2, 3, 4, 5};
for (auto& elem : vec) {
    elem *= 2;
}

Lambda 表达式

// 基本语法
auto lambda = [](int x, int y) { return x + y; };
int result = lambda(3, 4);  // 7

// 捕获变量
int a = 10;
auto captureByValue = [a](int x) { return x + a; };
auto captureByRef = [&a](int x) { a += x; };

// 捕获所有
auto captureAll = [=](int x) { return x + a; };
auto captureAllRef = [&](int x) { a += x; };

智能指针

#include <memory>

// unique_ptr:独占所有权
std::unique_ptr<int> ptr1 = std::make_unique<int>(42);
// std::unique_ptr<int> ptr2 = ptr1;  // 编译错误

// shared_ptr:共享所有权
std::shared_ptr<int> ptr3 = std::make_shared<int>(42);
std::shared_ptr<int> ptr4 = ptr3;  // 引用计数 +1

// weak_ptr:弱引用,不增加引用计数
std::weak_ptr<int> ptr5 = ptr3;

右值引用与移动语义

// 移动构造函数
class MyClass {
public:
    MyClass(MyClass&& other) noexcept
        : data_(std::move(other.data_)) {
        other.data_ = nullptr;
    }

    // 移动赋值运算符
    MyClass& operator=(MyClass&& other) noexcept {
        if (this != &other) {
            delete data_;
            data_ = std::move(other.data_);
            other.data_ = nullptr;
        }
        return *this;
    }

private:
    int* data_;
};

// std::move
std::string str1 = "Hello";
std::string str2 = std::move(str1);  // str1 现在为空

std::function 和 std::bind

#include <functional>

int add(int a, int b) { return a + b; }

// std::function:可调用对象的包装器
std::function<int(int, int)> func = add;
int result = func(3, 4);  // 7

// std::bind:绑定参数
auto add5 = std::bind(add, std::placeholders::_1, 5);
int result2 = add5(10);  // 15

// 绑定成员函数
struct Calculator {
    int multiply(int a, int b) { return a * b; }
};
Calculator calc;
auto multiplyBy2 = std::bind(&Calculator::multiply, &calc, std::placeholders::_1, 2);
int result3 = multiplyBy2(5);  // 10

std::unordered_map 和 std::unordered_set

#include <unordered_map>
#include <unordered_set>

// 哈希表
std::unordered_map<std::string, int> scores;
scores["Alice"] = 90;
scores["Bob"] = 85;

// 查找
if (scores.find("Alice") != scores.end()) {
    std::cout << "Alice's score: " << scores["Alice"] << "\n";
}

// unordered_set
std::unordered_set<int> uniqueValues = {1, 2, 2, 3, 3, 3};
// uniqueValues = {1, 2, 3}

std::tuple

#include <tuple>

// 创建 tuple
std::tuple<int, double, std::string> t{42, 3.14, "hello"};

// 获取元素
std::get<0>(t);  // 42
std::get<1>(t);  // 3.14
std::get<2>(t);  // "hello"

// 结构化绑定(C++17)
auto [id, value, name] = t;

// 连接 tuple
auto combined = std::tuple_cat(t, std::make_pair(true, 'a'));

std::chrono

#include <chrono>

// 时间点
auto now = std::chrono::system_clock::now();

//  duration
using namespace std::chrono_literals;
auto duration = 100ms;           // 100 毫秒
auto seconds = 2s;               // 2 秒
auto minutes = 5min;             // 5 分钟

// 睡眠
std::this_thread::sleep_for(500ms);

// 计时
auto start = std::chrono::high_resolution_clock::now();
// ... 执行操作
auto end = std::chrono::high_resolution_clock::now();
auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);

std::array

#include <array>

// 固定大小数组
std::array<int, 5> arr = {1, 2, 3, 4, 5};

// 访问元素
arr[0] = 10;
arr.at(1) = 20;

// 迭代
for (const auto& elem : arr) {
    std::cout << elem << " ";
}

// 大小
std::cout << "Size: " << arr.size() << "\n";  // 5

// 前后元素
std::cout << "Front: " << arr.front() << "\n";
std::cout << "Back: " << arr.back() << "\n";

// 填充
arr.fill(0);

std::forward_list

#include <forward_list>

// 单向链表
std::forward_list<int> list = {1, 2, 3, 4, 5};

// 在前面插入
list.push_front(0);

// 在指定位置后插入
auto it = list.begin();
list.insert_after(it, 100);

// 删除元素
list.pop_front();
list.erase_after(it);

// 遍历
for (const auto& elem : list) {
    std::cout << elem << " ";
}

// 检查是否为空
if (list.empty()) {
    std::cout << "List is empty\n";
}

std::random

#include <random>

// 随机数引擎
std::random_device rd;  // 硬件随机数生成器
std::mt19937 gen(rd()); // Mersenne Twister 引擎

// 均匀分布
std::uniform_int_distribution<> dis(1, 100);
int randomInt = dis(gen);  // 1-100 之间的随机整数

// 浮点数分布
std::uniform_real_distribution<> disReal(0.0, 1.0);
double randomDouble = disReal(gen);

// 正态分布
std::normal_distribution<> normal(5.0, 2.0);
double normalValue = normal(gen);

// 伯努利分布
std::bernoulli_distribution bernoulli(0.5);
bool coinFlip = bernoulli(gen);

std::regex

#include <regex>

// 正则表达式匹配
std::string text = "Hello, World! 123";
std::regex pattern(R"(\d+)");  // 匹配数字

std::smatch matches;
if (std::regex_search(text, matches, pattern)) {
    std::cout << "Found: " << matches[0] << "\n";  // 123
}

// 正则表达式替换
std::string result = std::regex_replace(text, std::regex(R"(\d+)"), "NUM");
std::cout << result << "\n";  // Hello, World! NUM

// 正则表达式迭代
std::regex word_pattern(R"(\w+)");
std::sregex_iterator it(text.begin(), text.end(), word_pattern);
std::sregex_iterator end;

for (; it != end; ++it) {
    std::cout << it->str() << "\n";
}

范围 for 循环

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

// 只读
for (const auto& elem : vec) {
    std::cout << elem << " ";
}

// 修改
for (auto& elem : vec) {
    elem *= 2;
}

// 数组
int arr[] = {1, 2, 3};
for (auto& x : arr) {
    x *= 2;
}

初始化列表

// 统一初始化
int x{42};
std::vector<int> vec{1, 2, 3, 4, 5};
std::map<std::string, int> m{
    {"apple", 1},
    {"banana", 2}
};

// 防止窄化转换
// int y{3.14};  // 编译错误

nullptr

void func(int* ptr) {}
void func(int x) {}

func(nullptr);  // 调用 func(int*)
// func(NULL);   // 可能有歧义

int* ptr = nullptr;

constexpr

constexpr int factorial(int n) {
    return n <= 1 ? 1 : n * factorial(n - 1);
}

constexpr int result = factorial(5);  // 编译期计算

类型别名

using String = std::string;
using IntVector = std::vector<int>;

// 模板别名
template<typename T>
using Vec = std::vector<T>;

Vec<int> v;  // std::vector<int>

委托构造函数

class MyClass {
public:
    MyClass(int x, int y) : x_(x), y_(y) {}

    // 委托给上面的构造函数
    MyClass(int x) : MyClass(x, 0) {}

    MyClass() : MyClass(0, 0) {}

private:
    int x_, y_;
};

override 和 final

class Base {
public:
    virtual void func() {}
    virtual void finalFunc() final {}
};

class Derived : public Base {
public:
    void func() override {}  // 明确表示重写

    // void finalFunc() override {}  // 编译错误,final 函数不能重写
};

class FinalClass final : public Base {
    // 不能被继承
};

enum class

enum class Color { Red, Green, Blue };
enum class Animal { Dog, Cat };

Color c = Color::Red;
// Color c2 = Red;  // 编译错误,需要作用域
// if (c == Animal::Dog) {}  // 编译错误,不同枚举类型不能比较

// 显式转换
int value = static_cast<int>(Color::Red);  // 0

静态断言

static_assert(sizeof(int) == 4, "int must be 4 bytes");

template<typename T>
void checkSize() {
    static_assert(sizeof(T) >= 4, "Type must be at least 4 bytes");
}

变参模板

// 打印任意数量的参数
template<typename... Args>
void print(Args... args) {
    ((std::cout << args << " "), ...);  // 折叠表达式(C++17)
    std::cout << "\n";
}

// 递归展开
template<typename T>
T sum(T first) {
    return first;
}

template<typename T, typename... Args>
T sum(T first, Args... rest) {
    return first + sum(rest...);
}

print(1, 2, 3, "hello");  // 1 2 3 hello
int total = sum(1, 2, 3, 4, 5);  // 15

常用特性总结

最常用的 C++11 特性:

  • auto 类型推导
  • Lambda 表达式
  • 智能指针(unique_ptr, shared_ptr
  • 范围 for 循环
  • nullptr
  • override 关键字
  • enum class

C++14:增量改进

C++14 是一个较小的更新,主要是对 C++11 的改进和补充。

泛型 Lambda

// C++11 只能指定具体类型
auto lambda1 = [](int x) { return x * 2; };

// C++14 支持 auto 参数
auto lambda2 = [](auto x) { return x * 2; };
lambda2(3);      // int
lambda2(3.14);   // double

Lambda 捕获初始化

int x = 42;
auto lambda = [y = x + 1]() { return y; };
// y 是 43,即使 x 改变也不影响

// 更复杂的捕获
auto ptr = std::make_unique<int>(100);
auto capturePtr = [p = std::move(ptr)]() { return *p; };

函数返回类型推导

// C++11 必须指定返回类型
auto add1(int x, int y) -> int {
    return x + y;
}

// C++14 可以推导返回类型
auto add2(int x, int y) {
    return x + y;
}

// 递归函数需要指定返回类型
auto factorial(int n) -> int {
    return n <= 1 ? 1 : n * factorial(n - 1);
}

变量模板

template<typename T>
constexpr T pi = T(3.1415926535897932385);

double d = pi<double>;   // 3.1415926535897932385
float f = pi<float>;     // 3.1415927f

// 其他变量模板
template<typename T>
constexpr std::size_t byte_count = sizeof(T);

std::size_t size = byte_count<int>;  // 4

二进制字面量

int x = 0b1010;  // 10
int y = 0b11111111;  // 255
int z = 0b1100'0101;  // 197

// 无符号
unsigned int flags = 0b0000'1111'0000'0000;

数字分隔符

int million = 1'000'000;
double pi = 3.14159'26535;
int binary = 0b1010'0101;
long long credit = 1'000'000'000'000LL;

// 十六进制
uint32_t mac = 0xDE'AD'BE'EF;

[[deprecated]] 属性

[[deprecated("Use newFunction instead")]]
void oldFunction() {}

// 使用
[[deprecated]] int deprecatedVar = 42;

放宽 constexpr 限制

// C++14 constexpr 函数可以有局部变量和循环
constexpr int factorial(int n) {
    int result = 1;
    for (int i = 2; i <= n; ++i) {
        result *= i;
    }
    return result;
}

constexpr int f = factorial(5);  // 120

库新增特性

std::make_unique

// C++11 没有 make_unique
std::unique_ptr<int> ptr1(new int(42));

// C++14 添加了 make_unique
std::unique_ptr<int> ptr2 = std::make_unique<int>(42);

// 数组
auto arr = std::make_unique<int[]>(10);

// 更安全:异常安全
auto smartPtr = std::make_unique<MyClass>(args...);

std::quoted

#include <iomanip>
#include <sstream>

std::string input = R"(Hello "World"!)";
std::stringstream ss;
ss << std::quoted(input);
std::cout << ss.str() << "\n";  // 输出: "Hello \"World\"!"

// 读取
std::string output;
ss >> std::quoted(output);  // output = Hello "World"!

std::exchange

// C++11 需要手动实现
template<typename T, typename U>
T exchange(T& obj, U&& newValue) {
    T oldValue = std::move(obj);
    obj = std::forward<U>(newValue);
    return oldValue;
}

// C++14 直接使用
std::vector<int> v{1, 2, 3};
std::vector<int> old = std::exchange(v, {4, 5});
// old = {1, 2, 3}, v = {4, 5}

std::integer_sequence

#include <utility>

// 编译时整数序列
template<std::size_t... Ints>
void printIndices(std::index_sequence<Ints...>) {
    ((std::cout << Ints << " "), ...);
}

printIndices(std::make_index_sequence<5>{});  // 0 1 2 3 4

// 应用到参数包
template<typename T, std::size_t... Is>
void printTupleElements(const T& t, std::index_sequence<Is...>) {
    ((std::cout << std::get<Is>(t) << " "), ...);
}

chrono 和 string 字面量

using namespace std::chrono_literals;

// 时间字面量
auto duration = 100ms;           // 100 毫秒
auto seconds = 2s;               // 2 秒
auto minutes = 5min;             // 5 分钟
auto hours = 1h;                 // 1 小时

// 组合使用
auto complexDuration = 1h + 30min + 45s;

// 字符串字面量(C++14)
auto str = "hello"s;  // std::string
auto u8str = u8"world"s;  // std::string (UTF-8)
auto wstr = L"wide"s;  // std::wstring

std::shared_timed_mutex

#include <shared_mutex>

class ReaderWriter {
    mutable std::shared_timed_mutex mtx_;
    std::vector<int> data_;

public:
    void write(int value) {
        std::unique_lock<std::shared_timed_mutex> lock(mtx_);
        data_.push_back(value);
    }

    std::vector<int> read() const {
        std::shared_lock<std::shared_timed_mutex> lock(mtx_);
        return data_;
    }
};

常用特性总结

最常用的 C++14 特性:

  • 泛型 Lambda
  • 函数返回类型推导
  • std::make_unique
  • 数字分隔符
  • 二进制字面量

C++17:重大更新

C++17 带来了许多重要的新特性,显著提升了 C++ 的表达力和安全性。

结构化绑定

// 解构 pair
std::pair<int, std::string> p{42, "hello"};
auto [id, name] = p;

// 解构 tuple
std::tuple<int, double, std::string> t{1, 3.14, "world"};
auto [x, y, z] = t;

// 解构数组
int arr[3] = {1, 2, 3};
auto [a, b, c] = arr;

// 解构结构体
struct Point {
    int x;
    int y;
};
Point pt{10, 20};
auto [px, py] = pt;

// 在范围 for 循环中使用
std::map<std::string, int> m{{"a", 1}, {"b", 2}};
for (const auto& [key, value] : m) {
    std::cout << key << ": " << value << "\n";
}

if 和 switch 初始化语句

// 传统方式
std::map<int, std::string> m;
auto it = m.find(42);
if (it != m.end()) {
    // 使用 it
}

// C++17 方式
if (auto it = m.find(42); it != m.end()) {
    // 使用 it
}

// 配合结构化绑定
std::map<int, std::string> m{{1, "one"}, {2, "two"}};
if (auto [it, inserted] = m.emplace(3, "three"); inserted) {
    std::cout << "Inserted: " << it->second << "\n";
}

// switch 初始化语句
switch (auto it = m.find(42); auto result = it->second) {
    case "found":
        break;
}

constexpr if

template<typename T>
auto getValue(T t) {
    if constexpr (std::is_pointer_v<T>) {
        return *t;
    } else {
        return t;
    }
}

int x = 42;
std::cout << getValue(x) << "\n";      // 42
std::cout << getValue(&x) << "\n";     // 42

折叠表达式

// 参数包展开
template<typename... Args>
auto sum(Args... args) {
    return (args + ...);  // 右折叠
}

// 使用
int total = sum(1, 2, 3, 4, 5);  // 15

// 左折叠
template<typename... Args>
auto printAll(Args... args) {
    (std::cout << ... << args) << "\n";
}

printAll(1, " ", 2, " ", 3);  // 1 2 3

// 空参数包
template<typename... Args>
void log(Args... args) {
    ((std::cout << args << "\n"), ...);
}

内联变量

// 头文件中定义静态成员变量
struct MyClass {
    static inline int value = 42;  // C++17
    static inline std::vector<int> data = {1, 2, 3};
};

// 全局变量
inline constexpr int MAX_SIZE = 1000;

// 不再需要在 .cpp 文件中定义

类模板参数推导(CTAD)

std::pair p{42, "hello"};           // std::pair<int, const char*>
std::tuple t{1, 2.0, "three"};      // std::tuple<int, double, const char*>

// 推导指引
template<typename T>
struct MyContainer {
    MyContainer(T val) : value_(val) {}
    T value_;
};

MyContainer c{42};  // MyContainer<int>

// 容器推导
std::vector v{1, 2, 3};  // std::vector<int>

嵌套命名空间

// C++17 之前
namespace outer::inner {
    void func() {}
}

// 等同于
namespace outer {
    namespace inner {
        void func() {}
    }
}

属性改进

// [[nodiscard]]:忽略返回值会警告
[[nodiscard]] int compute() {
    return 42;
}

// compute();  // 警告:返回值被忽略

// [[maybe_unused]]:抑制未使用警告
[[maybe_unused]] int x = 42;

// [[fallthrough]]:显式表示 switch 穿透
switch (value) {
    case 1:
        doSomething();
        [[fallthrough]];
    case 2:
        doSomethingElse();
        break;
}

// [[nodiscard("reason")]] 自定义消息
[[nodiscard("Connection must be closed")]]
Connection connect();

UTF-8 字符字面量

// UTF-8 字符字面量
char8_t c1 = u8'A';  // UTF-8 编码

// UTF-8 字符串字面量
auto str = u8"Hello, 世界!";  // const char8_t*

// Unicode 编码
char16_t c2 = u'汉';  // UTF-16
char32_t c3 = U'中';  // UTF-32

标准库新增特性

std::optional

#include <optional>

std::optional<int> divide(int a, int b) {
    if (b == 0) {
        return std::nullopt;  // 表示无值
    }
    return a / b;
}

auto result = divide(10, 2);
if (result) {
    std::cout << *result << "\n";  // 5
}

// 使用 value_or 提供默认值
int value = divide(10, 0).value_or(-1);  // -1

// 直接构造
std::optional<std::string> opt("hello");

std::variant

#include <variant>

std::variant<int, double, std::string> var;

var = 42;
std::cout << std::get<int>(var) << "\n";  // 42

// 使用 std::visit
auto visitor = [](auto&& arg) {
    std::cout << arg << "\n";
};
std::visit(visitor, var);

// 使用 std::holds_alternative 检查类型
if (std::holds_alternative<int>(var)) {
    std::cout << "Contains int\n";
}

// 获取索引
std::cout << var.index() << "\n";  // 0

std::any

#include <any>

std::any a = 42;
a = 3.14;
a = std::string("hello");

// 检查类型
if (a.type() == typeid(std::string)) {
    std::cout << std::any_cast<std::string>(a) << "\n";
}

// 使用 std::any_cast
try {
    int value = std::any_cast<int>(a);  // 抛出异常
} catch (const std::bad_any_cast& e) {
    std::cout << "Bad cast: " << e.what() << "\n";
}

std::string_view

#include <string_view>

// 避免字符串拷贝
void printString(std::string_view sv) {
    std::cout << sv << "\n";
}

std::string str = "hello";
const char* cstr = "world";

printString(str);      // OK
printString(cstr);     // OK
printString("test");   // OK

// 子串操作
std::string_view sv = "Hello, World!";
std::cout << sv.substr(0, 5) << "\n";  // Hello
std::cout << sv.starts_with("Hello") << "\n";  // true

std::byte

#include <cstddef>

// 字节类型,用于访问原始内存
std::byte b{42};

std::byte data[4];
data[0] = std::byte{0x12};
data[1] = std::byte{0x34};

// 转换为整数
int value = std::to_integer<int>(data[0]);  // 18

// 内存操作
std::memset(data, std::byte{0}, sizeof(data));

std::invoke

#include <functional>

// 调用函数指针
int add(int a, int b) { return a + b; }
int result = std::invoke(add, 3, 4);  // 7

// 调用成员函数
struct Calculator {
    int multiply(int a, int b) { return a * b; }
};
Calculator calc;
int product = std::invoke(&Calculator::multiply, calc, 3, 4);  // 12

// 调用 lambda
auto lambda = [](int a, int b) { return a * b; };
int lambdaResult = std::invoke(lambda, 5, 6);  // 30

std::apply

#include <tuple>

int add(int a, int b, int c) { return a + b + c; }

auto t = std::make_tuple(1, 2, 3);
int result = std::apply(add, t);  // 6

// 访问 tuple 元素
std::apply([](auto&... args) {
    ((std::cout << args << "\n"), ...);
}, t);

std::make_from_tuple

#include <tuple>

struct Point {
    int x;
    int y;
    int z;
};

auto t = std::make_tuple(1, 2, 3);
Point p = std::make_from_tuple<Point>(t);  // Point{1, 2, 3}

std::clamp

#include <algorithm>

int value = 75;
int minVal = 0;
int maxVal = 100;

int clamped = std::clamp(value, minVal, maxVal);  // 75
int clamped2 = std::clamp(-10, minVal, maxVal);   // 0
int clamped3 = std::clamp(150, minVal, maxVal);   // 100

// 带比较函数
auto clamped4 = std::clamp(value, minVal, maxVal, std::greater<int>());

std::reduce/std::transform_reduce

#include <numeric>
#include <execution>

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

// 并行归约
int sum = std::reduce(std::execution::par, vec.begin(), vec.end());

// 先转换后归约
auto squaredSum = std::transform_reduce(
    std::execution::par,
    vec.begin(), vec.end(),
    0LL,
    std::plus<>{},
    [](int x) { return x * x; }
);  // 55 (1+4+9+16+25)

std::filesystem

#include <filesystem>

namespace fs = std::filesystem;

// 创建目录
fs::create_directory("test");
fs::create_directories("a/b/c");  // 递归创建

// 遍历目录
for (const auto& entry : fs::directory_iterator(".")) {
    std::cout << entry.path() << "\n";
    std::cout << "Is file: " << entry.is_regular_file() << "\n";
}

// 检查文件
if (fs::exists("file.txt")) {
    std::cout << "File size: " << fs::file_size("file.txt") << "\n";
}

// 路径操作
fs::path p = "/home/user/documents/file.txt";
std::cout << "Filename: " << p.filename() << "\n";
std::cout << "Extension: " << p.extension() << "\n";
std::cout << "Parent: " << p.parent_path() << "\n";

// 相对路径
std::cout << "Relative: " << fs::relative(p) << "\n";

std::scoped_lock

#include <mutex>

std::mutex mtx1, mtx2;

// C++17 之前:手动 lock
std::lock(mtx1, mtx2);
std::lock_guard<std::mutex> lock1(mtx1, std::adopt_lock);
std::lock_guard<std::mutex> lock2(mtx2, std::adopt_lock);

// C++17:scoped_lock 自动管理多个锁
std::scoped_lock lock(mtx1, mtx2);
// 自动以避免死锁的方式获取所有锁
// 析构时自动释放

__has_include

#if __has_include(<optional>)
#include <optional>
#endif

#if __has_include(<filesystem>) && __has_include(<version>)
#include <filesystem>
#define HAS_FILESYSTEM 1
#else
#define HAS_FILESYSTEM 0
#endif

并行算法

#include <algorithm>
#include <execution>

std::vector<int> vec(1000000);
std::iota(vec.begin(), vec.end(), 0);

// 执行策略
std::sort(std::execution::par, vec.begin(), vec.end());  // 并行
std::sort(std::execution::seq, vec.begin(), vec.end());  // 顺序
std::sort(std::execution::par_unseq, vec.begin(), vec.end());  // 并行+向量化

// 并行查找
auto it = std::find(std::execution::par, vec.begin(), vec.end(), 42);

// 并行变换
std::transform(std::execution::par, vec.begin(), vec.end(), vec.begin(),
               [](int x) { return x * 2; });

std::shared_mutex

#include <shared_mutex>

class ThreadSafeCache {
    mutable std::shared_mutex mtx_;
    std::unordered_map<std::string, std::string> cache_;

public:
    // 读操作:使用共享锁
    std::string read(const std::string& key) const {
        std::shared_lock<std::shared_mutex> lock(mtx_);
        auto it = cache_.find(key);
        return it != cache_.end() ? it->second : "";
    }

    // 写操作:使用独占锁
    void write(const std::string& key, const std::string& value) {
        std::unique_lock<std::shared_mutex> lock(mtx_);
        cache_[key] = value;
    }
};

常用特性总结

最常用的 C++17 特性:

  • 结构化绑定
  • std::optional
  • std::variant
  • std::string_view
  • std::invoke
  • if 初始化语句
  • std::filesystem
  • [[nodiscard]] 属性

C++20:革命性更新

C++20 是继 C++11 之后最大的更新,引入了模块、协程、概念和 ranges 等重大特性。

Concepts(概念)

#include <concepts>

// 定义概念
template<typename T>
concept Integral = std::is_integral_v<T>;

template<typename T>
concept Addable = requires(T a, T b) {
    a + b;  // 必须支持 + 运算
};

// 使用概念约束模板
template<Integral T>
T add(T a, T b) {
    return a + b;
}

// requires 子句
template<typename T>
requires Addable<T>
T multiply(T a, T b) {
    return a * b;
}

// 简写语法
auto subtract = [](std::integral auto a, std::integral auto b) {
    return a - b;
};

// 标准概念
template<std::sortable T>
void sortContainer(std::vector<T>& vec) {
    std::sort(vec.begin(), vec.end());
}

Ranges(范围库)

#include <ranges>
#include <vector>
#include <algorithm>

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

// 过滤偶数
auto evens = vec | std::views::filter([](int x) { return x % 2 == 0; });

// 转换
auto squared = evens | std::views::transform([](int x) { return x * x; });

// 取前 3 个
auto result = squared | std::views::take(3);

// 链式调用
auto final = vec
    | std::views::filter([](int x) { return x % 2 == 0; })
    | std::views::transform([](int x) { return x * x; })
    | std::views::take(3);

// 使用
for (auto x : final) {
    std::cout << x << " ";  // 4 16 36
}

// 直接创建视图
auto view = std::views::iota(1, 10) | std::views::filter([](int x) { return x % 2; });

协程(Coroutines)

#include <coroutine>
#include <iostream>

// 简单的生成器
template<typename T>
struct Generator {
    struct promise_type {
        T value;
        Generator get_return_object() {
            return Generator{std::coroutine_handle<promise_type>::from_promise(*this)};
        }
        std::suspend_always initial_suspend() { return {}; }
        std::suspend_always final_suspend() noexcept { return {}; }
        std::suspend_always yield_value(T val) {
            value = val;
            return {};
        }
        void return_void() {}
        void unhandled_exception() { std::terminate(); }
    };

    std::coroutine_handle<promise_type> h;
    Generator(std::coroutine_handle<promise_type> handle) : h(handle) {}
    ~Generator() { if (h) h.destroy(); }

    bool next() {
        h.resume();
        return !h.done();
    }

    T value() { return h.promise().value; }
};

Generator<int> range(int start, int end) {
    for (int i = start; i < end; ++i) {
        co_yield i;
    }
}

// 使用
auto gen = range(1, 5);
while (gen.next()) {
    std::cout << gen.value() << " ";  // 1 2 3 4
}

模块(Modules)

// math.ixx (模块接口)
export module math;

export int add(int a, int b) {
    return a + b;
}

export int multiply(int a, int b) {
    return a * b;
}

// main.cpp
import math;
import <iostream>;

int main() {
    std::cout << add(2, 3) << "\n";  // 5
    return 0;
}

三路比较运算符(<=>)

#include <compare>

struct Point {
    int x;
    int y;

    // 自动生成所有比较运算符
    auto operator<=>(const Point&) const = default;
};

Point p1{1, 2};
Point p2{1, 3};

if (p1 < p2) { /* ... */ }
if (p1 == p2) { /* ... */ }
if (p1 != p2) { /* ... */ }

// 自定义比较
struct Version {
    int major;
    int minor;
    int patch;

    std::strong_ordering operator<=>(const Version& other) const {
        if (auto cmp = major <=> other.major; cmp != 0) return cmp;
        if (auto cmp = minor <=> other.minor; cmp != 0) return cmp;
        return patch <=> other.patch;
    }
};

Designated Initializers(指定初始化器)

struct Point {
    int x;
    int y;
    int z;
};

Point p{.x = 1, .z = 3};  // y 初始化为 0

// 数组
int arr[5] = {[1] = 10, [3] = 30};  // {0, 10, 0, 30, 0}

// 结构体数组
Point points[] = {{.x = 1}, {.y = 2}, {.z = 3}};

consteval 和 constinit

// consteval:必须在编译期求值
consteval int square(int x) {
    return x * x;
}

constexpr int result = square(5);  // OK
// int x = 5;
// int y = square(x);  // 编译错误,x 不是常量

// constinit:必须在编译期初始化
constinit int global = 42;

// 结合使用
consteval int compute(int x) { return x * 2; }
constinit int computed = compute(42);

范围 for 循环支持初始化器

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

// C++20 之前
for (auto& elem : vec) {
    elem *= 2;
}

// C++20:在循环中声明变量
for (auto vecCopy = vec; auto& elem : vecCopy) {
    // 使用 vecCopy
    elem *= 2;
}

// 更复杂的用法
for (auto it = vec.begin(), end = vec.end(); auto& elem : vec) {
    // 使用 it 和 end
}

Lambda 模板参数列表

// C++20 之前
auto lambda1 = [](auto x) { return x * 2; };

// C++20:显式模板参数
auto lambda2 = []<typename T>(T x) { return x * 2; };

// 多个模板参数
auto lambda3 = []<typename T, typename U>(T a, U b) {
    return a + b;
};

// 模板参数默认值
auto lambda4 = []<typename T = int>(T x) { return x; };

// 在 requires 子句中使用
auto lambda5 = []<typename T>(T x) requires std::integral<T> {
    return x * 2;
};

[[no_unique_address]] 属性

struct Empty {};

struct A {
    int x;
    Empty e;  // 不占用空间
};

struct B {
    int x;
    [[no_unique_address]] Empty e;  // 编译器可以优化,不占用额外空间
};

// 编译器可能将 B 的大小优化为与 int 相同
static_assert(sizeof(B) == sizeof(int));

[[likely]] 和 [[unlikely]] 属性

int process(int value) {
    switch (value) {
        [[likely]] case 1:
            return 10;
        [[unlikely]] case 2:
            return 20;
        default:
            return 0;
    }
}

bool check(int x) {
    if (x > 0) [[likely]] {
        return true;
    }
    return false;
}

void logMessage(int level) {
    if (level > 100) [[unlikely]] {
        // 警告:这很少见
    }
}

标准库新增特性

std::format

#include <format>

std::string name = "Alice";
int age = 30;

// 类似 Python 的格式化
std::string s1 = std::format("Name: {}, Age: {}", name, age);

// 带索引
std::string s2 = std::format("{1} is {0} years old", age, name);

// 格式化选项
std::string s3 = std::format("Pi: {:.2f}", 3.14159);  // Pi: 3.14
std::string s4 = std::format("Hex: {:#x}", 255);      // Hex: 0xff
std::string s5 = std::format("Padding: {:>10}", "test");  // Padding:      test
std::string s6 = std::format("Zeros: {:0>5}", 42);    // Zeros: 00042

std::span

#include <span>

void processArray(std::span<int> arr) {
    for (auto x : arr) {
        std::cout << x << " ";
    }
}

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

processArray(arr);   // OK
processArray(vec);   // OK

// 子视图
std::span<int> sub(arr, 3);  // 前 3 个元素

// 动态大小
std::span<int> dynamic(vec.data(), vec.size());

std::source_location

#include <source_location>

void log(const std::string& msg,
         std::source_location loc = std::source_location::current()) {
    std::cout << loc.file_name() << ":" << loc.line() << " "
              << loc.function_name() << ": " << msg << "\n";
}

void foo() {
    log("Hello");  // 自动记录调用位置
}

std::bit_cast

#include <bit>

// 类型重新解释
float f = 3.14f;
uint32_t bits = std::bit_cast<uint32_t>(f);

// 位反转
struct Packed {
    uint32_t x : 10;
    uint32_t y : 10;
    uint32_t z : 10;
};

uint32_t raw = 0xABCDEF;
Packed p = std::bit_cast<Packed>(raw);

std::endian

#include <bit>

// 检查字节序
if (std::endian::native == std::endian::little) {
    // 小端字节序
}

// 字节序转换
uint32_t x = 0x12345678;
uint32_t swapped = std::byteswap(x);

std::make_shared 支持数组

// C++20 之前
auto arr = std::make_shared<std::vector<int>>(10, 0);

// C++20 支持数组
auto arr2 = std::make_shared<int[]>(10);
arr2[0] = 1;
arr2[1] = 2;

// 多维数组
auto matrix = std::make_shared<int[][3]>(5);

contains 成员函数

std::set<int> s = {1, 2, 3, 4, 5};

// C++20 之前
if (s.find(3) != s.end()) { /* ... */ }

// C++20
if (s.contains(3)) { /* ... */ }

// 同样适用于 map, unordered_map, unordered_set
std::map<std::string, int> m{{"a", 1}, {"b", 2}};
if (m.contains("a")) { /* ... */ }

starts_with 和 ends_with

std::string str = "Hello, World!";

if (str.starts_with("Hello")) { /* ... */ }
if (str.ends_with("!")) { /* ... */ }

// 同样适用于 string_view
std::string_view sv = "test.txt";
if (sv.ends_with(".txt")) { /* ... */ }

// C++23 也添加到了 std::string::contains

并发特性

std::jthread

#include <thread>

std::jthread jt([](std::stop_token st) {
    while (!st.stop_requested()) {
        // 执行任务
    }
});

// 析构时自动 join
// 或者显式请求停止
jt.request_stop();

std::stop_token

#include <thread>

void worker(std::stop_token st, int id) {
    while (!st.stop_requested()) {
        // 工作
        std::this_thread::sleep_for(100ms);
    }
}

std::jthread t1(worker, 1);
std::jthread t2(worker, 2);

// 请求停止
t1.request_stop();
t2.request_stop();

// 所有 jthread 析构时自动 join

信号量(Semaphores)

#include <semaphore>

std::counting_semaphore<5> sem(5);  // 最多 5 个许可

void worker() {
    sem.acquire();  // 获取许可
    // 临界区
    sem.release();  // 释放许可
}

// 二进制信号量
std::binary_semaphore bs(1);
std::binary_semaphore bs2(0);  // 初始为 0

Barriers

#include <barrier>

auto phase1 = [] { /* 第一阶段工作 */ };
auto phase2 = [] { /* 第二阶段工作 */ };

std::barrier barrier(2, [] { /* 阶段完成回调 */ });

std::thread t1([&] {
    phase1();
    barrier.arrive_and_wait();  // 等待 t2
    phase2();
});

std::thread t2([&] {
    phase1();
    barrier.arrive_and_wait();  // 等待 t1
    phase2();
});

Latches

#include <latch>

std::latch workDone(3);  // 3 个工作线程

void worker(int id) {
    // 做工作
    workDone.count_down();  // 标记完成
}

void master() {
    // 等待所有工作完成
    workDone.wait();

    // 继续
}

Atomic wait/notify

#include <atomic>

std::atomic<int> counter{0};

// 等待直到值改变
int oldValue = counter.load();
while (counter.wait(oldValue) == oldValue) {
    // 值未改变,继续等待
}

// 通知所有等待的线程
counter.store(1);
counter.notify_all();

std::atomic<std::shared_ptr>

#include <atomic>
#include <memory>

struct Node {
    int value;
    std::atomic<std::shared_ptr<Node>> next;
};

std::atomic<std::shared_ptr<Node>> head;

// 原子地读取
std::shared_ptr<Node> current = head.load();

// 原子地 CAS
std::shared_ptr<Node> newNode = std::make_shared<Node>();
std::shared_ptr<Node> expected = head.load();
do {
    newNode->next = expected;
} while (!head.compare_exchange_weak(expected, newNode));

常用特性总结

最常用的 C++20 特性:

  • Concepts(概念)
  • Ranges(范围库)
  • 三路比较运算符(<=>
  • std::format
  • std::span
  • contains 成员函数
  • starts_with / ends_with
  • std::jthread

C++23:最新特性

C++23 是最新的标准,继续完善和扩展 C++ 的功能。

Deducing this(推导 this)

struct Widget {
    void process(this auto&& self) {
        // self 可以是左值引用、右值引用或 const 引用
        self.doSomething();
    }

    void doSomething() & {
        std::cout << "Lvalue\n";
    }

    void doSomething() && {
        std::cout << "Rvalue\n";
    }
};

Widget w;
w.process();        // Lvalue
Widget{}.process(); // Rvalue

if consteval

constexpr int compute(int x) {
    if consteval {
        // 编译期执行的代码
        return x * 2;
    } else {
        // 运行期执行的代码
        return x * 3;
    }
}

constexpr int result = compute(5);  // 10 (编译期)
int runtime = compute(5);  // 15 (运行期)

auto(x) 和 auto{x}

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

// 强制拷贝
auto copy = auto(vec);  // vec 的副本

// 强制移动
auto moved = auto(std::move(vec));  // 移动构造

// 括号形式
auto copy2 = auto{vec};

静态运算符(Static Operators)

struct Number {
    int value;

    static Number operator+(Number a, Number b) {
        return Number{a.value + b.value};
    }

    static Number operator-(Number a, Number b) {
        return Number{a.value - b.value};
    }
};

Number n1{1};
Number n2{2};
Number n3 = n1 + n2;  // Number{3}
Number n4 = n1 - n2;  // Number{-1}

多维 operator[]

// C++23 之前
data[0][1][2];

// C++23:支持多维 operator[]
template<typename T>
class Tensor3D {
    T* data_;
    std::size_t dim1_, dim2_, dim3_;

public:
    Tensor3D(T* data, std::size_t d1, std::size_t d2, std::size_t d3)
        : data_(data), dim1_(d1), dim2_(d2), dim3_(d3) {}

    // C++23 多维 operator[]
    auto operator[](std::size_t i) requires std::is_array_v<T> {
        return std::mdspan(data_ + i * dim2_ * dim3_, dim2_, dim3_);
    }
};

[[assume]] 属性

int divide(int a, int b) {
    [[assume(b != 0)]];  // 告诉编译器 b 不为 0
    return a / b;
}

int process(int value) {
    if (value < 0 || value > 100) [[assume(false)]];
    // 编译器知道 value 在 [0, 100] 范围内
    return value * 2;
}

size_t 字面量后缀

// C++23 字面量后缀
using namespace std::literals;

std::size_t a = 123uz;  // size_t
std::size_t b = 0uz;    // 空指针安全的 size_t

// 与 sizeof 配合
auto size = sizeof(int)uz;

std::print 和 std::println

#include <print>

std::print("Hello, World!\n");
std::println("Hello, World!");  // 自动换行

// 格式化
std::println("Name: {}, Age: {}", "Alice", 30);

// 支持容器
std::vector<int> vec = {1, 2, 3};
std::println("Vector: {}", vec);  // Vector: [1, 2, 3]

// 支持格式化选项
std::println("Pi: {:.2f}", 3.14159);  // Pi: 3.14
std::println("Binary: {:b}", 42);     // Binary: 101010

// 输出到文件
std::println(stdout, "To stdout");

标准库模块

// 导入标准库模块而不是头文件
import std;

// 不再需要 #include <iostream>, <vector>, 等
int main() {
    std::println("Hello, World!");
    std::vector<int> vec = {1, 2, 3};
    return 0;
}

std::expected

#include <expected>

std::expected<int, std::string> divide(int a, int b) {
    if (b == 0) {
        return std::unexpected("Division by zero");
    }
    return a / b;
}

auto result = divide(10, 2);
if (result) {
    std::println("Result: {}", *result);
} else {
    std::println("Error: {}", result.error());
}

// 使用 value_or
int value = divide(10, 0).value_or(-1);

// 链式操作
auto final = divide(10, 2).transform([](int x) { return x * 2; });

std::generator

#include <generator>

std::generator<int> range(int start, int end) {
    for (int i = start; i < end; ++i) {
        co_yield i;
    }
}

for (auto x : range(1, 5)) {
    std::println("{}", x);  // 1 2 3 4
}

// 生成器组合
std::generator<int> fibonacci() {
    int a = 0, b = 1;
    while (true) {
        co_yield a;
        auto next = a + b;
        a = b;
        b = next;
    }
}

std::mdspan

#include <mdspan>

int data[12] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};

// 3x4 矩阵视图
std::mdspan<int, std::extents<std::size_t, 3, 4>> mat(data);

std::println("mat[1][2] = {}", mat[1][2]);  // 7

// 动态维度
std::mdspan<int, std::dextents<std::size_t, 2>> dyn(data, 3, 4);

// 切片视图
std::mdspan row = std::submdspan(mat, std::slice{1, 1, 2});  // 第一行的一部分

std::flat_map 和 std::flat_set

#include <flat_map>
#include <flat_set>

// 扁平化容器,使用排序的 vector 存储
std::flat_map<std::string, int> map;
map["a"] = 1;
map["b"] = 2;

// 保持排序
map.sort();  // 按键排序

// 快速查找
if (map.contains("a")) {
    auto it = map.find("a");
}

std::flat_set<int> set = {3, 1, 4, 1, 5};  // 自动去重和排序

// 范围操作
auto range = map.equal_range("b");

std::byteswap

#include <bit>

uint32_t x = 0x12345678;
uint32_t y = std::byteswap(x);  // 0x78563412

// 大小端转换
uint16_t a = 0xABCD;
uint16_t swapped = std::byteswap(a);  // 0xCDAB

std::to_underlying

#include <type_traits>

enum class Color : int { Red = 1, Green = 2, Blue = 3 };

Color c = Color::Red;
int value = std::to_underlying(c);  // 1

// 强转等价但更清晰
auto val = std::to_underlying(Color::Green);  // 2

std::string::contains

std::string str = "Hello, World!";

// C++23 之前
if (str.find("World") != std::string::npos) { /* ... */ }

// C++23
if (str.contains("World")) { /* ... */ }
if (str.contains('o')) { /* ... */ }

// string_view 也有 contains
std::string_view sv = "test.txt";
if (sv.contains("test")) { /* ... */ }

std::unreachable

#include <utility>

int process(int value) {
    switch (value) {
        case 1:
            return 10;
        case 2:
            return 20;
        default:
            std::unreachable();  // 告诉编译器这里不可达
    }
}

void* allocate(std::size_t size) {
    if (size == 0) {
        return nullptr;
    }
    // 编译器知道 size > 0
    std::unreachable();
}

常用特性总结

最常用的 C++23 特性:

  • std::printstd::println
  • std::expected
  • std::generator
  • std::flat_mapstd::flat_set
  • 标准库模块(import std
  • std::byteswap
  • std::string::contains

日常开发必备

C++11:

  • auto - 几乎无处不在
  • Lambda 表达式 - 回调和算法
  • 智能指针 - 资源管理
  • 范围 for 循环 - 遍历容器
  • nullptr - 空指针
  • override - 虚函数重写

C++14:

  • 泛型 Lambda - 更灵活的 lambda
  • std::make_unique - 创建 unique_ptr
  • 数字分隔符 - 提高可读性

C++17:

  • 结构化绑定 - 解构返回值
  • std::optional - 可选值
  • std::string_view - 避免字符串拷贝
  • std::invoke - 统一调用接口
  • std::filesystem - 文件系统操作
  • [[nodiscard]] - 防止忽略返回值

C++20:

  • Concepts - 模板约束
  • Ranges - 函数式风格处理序列
  • std::format - 格式化输出
  • std::span - 数组视图
  • contains - 容器查找

C++23:

  • std::print / std::println - 简化输出
  • std::expected - 错误处理
  • std::generator - 生成器

兼容性考虑

  • C++11 - 所有现代编译器完全支持
  • C++14 - GCC 5+, Clang 3.4+, MSVC 2015+
  • C++17 - GCC 7+, Clang 5+, MSVC 2017 15.8+
  • C++20 - GCC 10+, Clang 12+, MSVC 2022 16.10+
  • C++23 - GCC 13+, Clang 16+, MSVC 2022 17.5+