现代 C++ 演进之旅:从 C++11 到 C++20 的核心特性与最佳实践 C++ 语言自 2011 年发布 C++11 标准以来,经历了革命性的变化。本文系统梳理了从 C++11 到 C++20 每个版本中最重要的特性、编程习惯和最佳实践,帮助你全面了解现代 C++ 的发展脉络。
C++11:现代 C++ 的开端 C++11 是一次里程碑式的更新,引入了众多改变编程方式的特性。
1. 自动类型推导 (auto) 1 2 3 4 5 6 7 std::vector<int >::iterator it = vec.begin ();auto it = vec.begin (); auto x = 5 ; auto name = "Hello" ;
2. 基于范围的 for 循环 1 2 3 4 5 6 7 8 9 for (std::vector<int >::iterator it = vec.begin (); it != vec.end (); ++it) { std::cout << *it << std::endl; }for (auto & value : vec) { std::cout << value << std::endl; }
3. 智能指针 1 2 3 4 5 6 7 8 9 10 #include <memory> std::unique_ptr<MyClass> ptr1 = std::make_unique <MyClass>(); std::shared_ptr<MyClass> ptr2 = std::make_shared <MyClass>(); std::weak_ptr<MyClass> weak_ptr = ptr2;
4. Lambda 表达式 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 struct Compare { bool operator () (int a, int b) const { return a < b; } }; std::sort (vec.begin (), vec.end (), Compare ()); std::sort (vec.begin (), vec.end (), [](int a, int b) { return a < b; });int threshold = 42 ; std::find_if (vec.begin (), vec.end (), [threshold](int value) { return value > threshold; });
5. 右值引用和移动语义 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 class MyString {public : MyString (MyString&& other) noexcept : data_ (other.data_), size_ (other.size_) { other.data_ = nullptr ; other.size_ = 0 ; } MyString& operator =(MyString&& other) noexcept { if (this != &other) { delete [] data_; data_ = other.data_; size_ = other.size_; other.data_ = nullptr ; other.size_ = 0 ; } return *this ; } private : char * data_; size_t size_; };
6. nullptr 1 2 3 4 5 6 void foo (int * ptr) {}foo (NULL ); foo (nullptr );
7. 委托构造函数和继承构造函数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 class MyClass {public : MyClass () : MyClass (0 , "default" ) {} MyClass (int value, const std::string& name) : value_ (value), name_ (name) {} private : int value_; std::string name_; };class Base {public : Base (int value) : value_ (value) {}protected : int value_; };class Derived : public Base {public : using Base::Base; };
8. override 和 final 说明符 1 2 3 4 5 6 7 8 9 10 11 class Base {public : virtual void foo () const ; virtual void bar () final ; };class Derived : public Base {public : void foo () const override ; };
9. 强类型枚举 (enum class) 1 2 3 4 5 6 7 8 9 enum Color { Red, Green, Blue }; int Red = 5 ; enum class Color { Red, Green, Blue }; Color c = Color::Red; int i = static_cast <int >(Color::Red);
10. 静态断言 (static_assert) 1 2 3 static_assert (sizeof (int ) == 4 , "int must be 4 bytes" );static_assert (sizeof (void *) == 8 , "Requires 64-bit platform" );
11. 类型别名模板 (using) 1 2 3 4 5 template <typename T>using StringMap = std::map<std::string, T>; StringMap<int > name_to_age;
12. 并发支持 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 #include <thread> #include <mutex> #include <future> std::thread t ([](){ std::cout << "Hello from thread!" << std::endl; }) ; t.join (); std::mutex mtx;std::lock_guard<std::mutex> lock (mtx) ; auto future = std::async (std::launch::async, [](){ return some_heavy_computation (); });auto result = future.get ();
C++14:改进与优化 C++14 是 C++11 的小幅扩展,主要改进了一些特性的易用性。
1. 函数返回类型推导 1 2 3 4 5 6 7 8 9 auto add (int a, int b) { return a + b; }auto & get_largest (std::vector<int >& vec) { return *std::max_element (vec.begin (), vec.end ()); }
2. 泛型 Lambda 1 2 3 4 5 6 7 8 auto print = [](const auto & value) { std::cout << value << std::endl; };print (42 ); print ("Hello" ); print (3.14 );
3. 变量模板 1 2 3 4 5 6 template <typename T>constexpr T pi = T (3.1415926535897932385 );float area = pi<float > * radius * radius;double circumference = 2 * pi<double > * radius;
4. constexpr 函数增强 1 2 3 4 5 6 7 8 9 10 constexpr int factorial (int n) { int result = 1 ; for (int i = 1 ; i <= n; ++i) { result *= i; } return result; }static_assert (factorial (5 ) == 120 , "Factorial computation error" );
C++17:重大更新 C++17 带来了许多重要的新特性,显著提升了代码表达能力和性能。
1. 结构化绑定 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 std::pair<int , std::string> get_pair () { return {42 , "answer" }; }auto p = get_pair ();int value = p.first; std::string str = p.second;auto [value, str] = get_pair (); std::map<int , std::string> my_map;if (auto [iter, success] = my_map.insert ({key, value}); success) { }
2. std::optional 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 #include <optional> std::optional<std::string> find_user (int id) { if (id == 1 ) return "Alice" ; return std::nullopt ; }if (auto user = find_user (1 )) { std::cout << "Found: " << *user << std::endl; } else { std::cout << "User not found" << std::endl; } std::cout << find_user (99 ).value_or ("Unknown" ) << std::endl;
3. std::variant 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 #include <variant> #include <string> std::variant<int , std::string, double > value; value = 42 ; value = "hello" ; std::visit ([](auto && arg) { using T = std::decay_t <decltype (arg)>; if constexpr (std::is_same_v<T, int >) { std::cout << "int: " << arg << std::endl; } else if constexpr (std::is_same_v<T, std::string>) { std::cout << "string: " << arg << std::endl; } else if constexpr (std::is_same_v<T, double >) { std::cout << "double: " << arg << std::endl; } }, value);
4. std::string_view 1 2 3 4 5 6 7 8 9 10 11 12 13 #include <string_view> void process_text (std::string_view text) { std::cout << "Length: " << text.length () << std::endl; std::cout << "First 5 chars: " << text.substr (0 , 5 ) << std::endl; } std::string str = "Hello World" ;process_text (str); process_text ("Hello World" );
5. 内联变量 1 2 3 4 5 6 7 8 inline constexpr double pi = 3.141592653589793 ;class MyClass {public : static inline int counter = 0 ; };
6. if 和 switch 的初始化语句 1 2 3 4 5 6 7 8 9 10 if (std::lock_guard lock (mutex); shared_data.ready ()) { } switch (auto value = get_value (); value.status ()) { case Status::Ok: break ; case Status::Error: break ; }
7. 并行算法 1 2 3 4 5 6 7 8 9 10 11 12 #include <algorithm> #include <execution> std::vector<int > data = {5 , 3 , 2 , 6 , 1 , 4 }; std::sort (std::execution::par, data.begin (), data.end ()); std::transform (std::execution::par, data.begin (), data.end (), data.begin (), [](int x) { return x * 2 ; });
8. 文件系统库 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 #include <filesystem> namespace fs = std::filesystem;for (const auto & entry : fs::directory_iterator ("." )) { if (entry.is_regular_file ()) { std::cout << "File: " << entry.path () << " Size: " << entry.file_size () << std::endl; } } fs::create_directories ("/tmp/example/subdir" );if (fs::exists ("file.txt" )) { fs::rename ("file.txt" , "file_renamed.txt" ); }
C++20:重大革新 C++20 是自 C++11 以来最重要的更新,引入了改变编程范式的特性。
1. 概念 (Concepts) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 #include <concepts> template <typename T>concept Arithmetic = std::integral<T> || std::floating_point<T>;template <typename T>concept Addable = requires (T a, T b) { { a + b } -> std::same_as<T>; };template <Arithmetic T>T add (T a, T b) { return a + b; }auto multiply (Arithmetic auto a, Arithmetic auto b) { return a * b; }template <typename T>requires Arithmetic<T> && Addable<T>T compute (T a, T b) { return add (a, b) * multiply (a, b); }
2. 范围库 (Ranges) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 #include <ranges> #include <vector> #include <iostream> namespace views = std::views; std::vector<int > numbers = {1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 };auto result = numbers | views::filter ([](int n) { return n % 2 == 0 ; }) | views::transform ([](int n) { return n * n; }) | views::take (3 ); for (int n : result) { std::cout << n << ' ' ; } std::vector<int > data = {5 , 3 , 2 , 6 , 1 , 4 }; std::ranges::sort (data);
3. 协程 (Coroutines) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 #include <coroutine> #include <iostream> #include <vector> template <typename T>struct Generator { struct promise_type { T current_value; auto get_return_object () { return Generator{this }; } auto initial_suspend () { return std::suspend_always{}; } auto final_suspend () noexcept { return std::suspend_always{}; } void unhandled_exception () { std::terminate (); } auto yield_value (T value) { current_value = value; return std::suspend_always{}; } void return_void () {} }; using Handle = std::coroutine_handle<promise_type>; Handle coro; explicit Generator (promise_type* p) : coro(Handle::from_promise(*p)) { } ~Generator () { if (coro) coro.destroy (); } T value () const { return coro.promise ().current_value; } bool next () { if (!coro.done ()) { coro.resume (); return !coro.done (); } return false ; } };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 () << ' ' ; }
4. 三路比较运算符 (<=>) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 #include <compare> class Point {public : int x; int y; auto operator <=>(const Point&) const = default ; }; Point p1{1 , 2 }, p2{3 , 4 };if (p1 < p2) { std::cout << "p1 is less than p2" << std::endl; }class CaseInsensitiveString {public : std::string value; std::strong_ordering operator <=>(const CaseInsensitiveString& other) const { return case_insensitive_compare (value, other.value) <=> 0 ; } bool operator ==(const CaseInsensitiveString& other) const { return case_insensitive_compare (value, other.value) == 0 ; } private : static int case_insensitive_compare (const std::string& a, const std::string& b) { return 0 ; } };
5. 模块 (Modules) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 export module math;export int add (int a, int b) { return a + b; }export double multiply (double a, double b) { return a * b; }import math;import <iostream>;int main () { std::cout << add (2 , 3 ) << std::endl; std::cout << multiply (2.5 , 4.0 ) << std::endl; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 #include <format> #include <iostream> std::string message = std::format("Hello, {}! The answer is {}." , "world" , 42 );double pi = 3.1415926535 ; std::string pi_str = std::format("{:.2f}" , pi); std::string s = std::format("{1} {0}" , "world" , "Hello" ); std::cout << std::format("Value: {:08d}" , 42 ) << std::endl;
7. std::span 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 #include <span> #include <vector> #include <array> void process_data (std::span<const int > data) { for (int value : data) { } } std::vector<int > vec = {1 , 2 , 3 , 4 , 5 }; std::array<int , 3> arr = {6 , 7 , 8 };int c_array[] = {9 , 10 , 11 };process_data (vec); process_data (arr); process_data (c_array);
总结与最佳实践 现代 C++ 提供了丰富的特性来编写更安全、更高效、更易读的代码。以下是一些最佳实践建议:
优先使用智能指针 管理动态内存,避免手动 new/delete
使用 std::string_view 作为函数参数接收字符串,避免不必要的拷贝
使用 auto 简化代码,但要在类型明显或重要时保持显式类型声明
使用范围 for 循环 遍历容器,代码更简洁
使用 nullptr 代替 NULL 或 0 表示空指针
使用 enum class 代替传统枚举,避免命名污染和隐式转换
使用 constexpr 将计算移至编译期,提高运行时性能
使用标准库算法 代替手写循环,代码更表达意图
使用 std::optional 表示可选值,避免特殊值标记
使用 std::variant 实现类型安全的联合体
使用概念 约束模板参数,使错误信息更友好
使用范围库 编写声明式、可组合的数据处理管道
使用模块 代替头文件,提高编译速度和代码隔离性
避免使用已弃用的特性,如 std::auto_ptr、std::bind1st、std::bind2nd 等,以及 C 风格的字符串函数和内存管理。
通过采用这些现代 C++ 特性,你可以编写出更健壮、更高效、更易维护的代码,充分发挥 C++ 作为系统级编程语言的强大能力。