自 C++11 起,C++ 经历了一场脱胎换骨的现代化变革。移动语义、Lambda、智能指针让 C++ 从"带类的 C"演变为一门表达能力媲美高层语言的系统级语言;C++20 的 Concepts、Ranges、Coroutines 三大特性更是将 C++ 推向了新的抽象高度;C++23 和即将到来的 C++26 则继续在并发、容器、类型系统等方向深耕。
本专题旨在逐一解剖这些关键特性——不讲"是什么"的表层,而是追问"为什么这样设计""编译器在背后做了什么""正确用法和致命陷阱分别在哪里"。
自 C++11 起,C++ 经历了一场脱胎换骨的现代化变革。移动语义、Lambda、智能指针让 C++ 从"带类的 C"演变为一门表达能力媲美高层语言的系统级语言;C++20 的 Concepts、Ranges、Coroutines 三大特性更是将 C++ 推向了新的抽象高度;C++23 和即将到来的 C++26 则继续在并发、容器、类型系统等方向深耕。
本专题旨在逐一解剖这些关键特性——不讲"是什么"的表层,而是追问"为什么这样设计""编译器在背后做了什么""正确用法和致命陷阱分别在哪里"。
C++11 引入 auto 和 decltype 之后,"类型"不再总是需要用手写。但这套推导规则有三个不同机制——auto、decltype(auto)、decltype(expression)——它们各自按不同的逻辑工作。更微妙的是,当 auto&& 遇到万能引用,或者 decltype 遇到括号,行为会发生令人意外的翻转。
本文从模板实参推导的规则出发,把这三条推导路径的差异,以及日常使用中最容易踩的坑,逐一说清楚。
在 C++98 时代,编译期计算几乎等同于模板元编程(TMP)——用递归模板 + 特化在类型系统里模拟图灵完备的计算。代码晦涩,编译慢,出错信息堪称灾难。C++11 引入了 constexpr,承诺让"正常 C++ 代码"在编译期运行。此后每一个标准版本都在放宽它的能力边界,到 C++20/23,你几乎可以在编译期做任何事。
本文梳理 constexpr 从 C++11 到 C++23 的演进历程,重点解释 if constexpr、consteval、constinit 三个极易混淆的概念,以及编译期容器的内存模型。
Lambda 是 C++11 引入的最具表现力的特性之一。它让"在现场定义一个可调用对象"从手写函数对象的繁琐中解放出来,直接改变了我们使用 STL 算法、注册回调、写异步代码的方式。
但 Lambda 的底层模型并不简单。"捕获"到底意味着什么?泛型 Lambda 的 auto 和模板 Lambda 的模板参数有什么区别?Lambda 对象在内存中究竟长什么样?本文从编译器视角出发,把这些问题一一拆解。
移动语义是 C++11 最重要的特性,没有之一。它让"把一个对象"交给另一个对象从昂贵的深拷贝变成了廉价的指针交换,从根本上改变了我们设计 C++ API 的方式。
但即便是用了多年 C++11 的开发者,仍然有很多人说不清楚三件事:std::move 到底做了什么?完美转发为什么叫"完美"?return 语句前面要不要加 std::move?
本文从值类别(value category)的本原出发,逐步拆开移动语义的每一个层次。
如果说异常安全是 C++ 资源管理的"正确性底线",那么智能指针就是将这条底线从"依赖程序员纪律"内化为"类型系统强制保证"的关键机制。C++11 彻底终结了 std::auto_ptr 的历史欠账,引入了 unique_ptr、shared_ptr 和 weak_ptr 三件套,并用移动语义解决了"独占所有权"的表达问题。
本文从 RAII 的根本原则出发,逐一拆解这三种智能指针的设计取舍、内存布局细节,以及那些编译器不报错但运行时必定翻车的陷阱。