Skip to content

C++11~20 特性清单与 constexpr / default / delete / nullptr

用于「介绍一下 C++11 新特性/了解哪些 C++20」这类暖场的系统化回答框架。

一、C++11 ~ C++20 特性总账(回答时可分点挑)

C++11(最常考)

  • 语言:auto/decltype 类型推导、右值引用与移动语义、lambda、range-for、nullptrenum class、constexpr、default/delete、可变参数模板、委托构造、explicit(转换)、override/finalstatic_assert、thread_local。
  • std::thread、智能指针(unique/shared/weak)、std::function/std::bindstd::array/unordered_*/tuplestd::atomic、时间库 chrono、std::move/std::forwardstd::begin/end、regex、random。

C++14

  • 泛型 lambda(auto 参数)、函数返回类型 auto 推导、make_uniquestd::integer_sequence、变量模板、if constexpr(实际C++17)… 库:std::shared_timed_mutex 等。

C++17

  • 结构化绑定、if/switch 初始化语句、inline 变量(解决头文件 static/全局定义)、fold 表达式(可变参)、if constexpr、filesystem、类模板参数推导 (CTAD)。
  • 库:std::optional / variant / anystring_viewshared_mutexstd::bytestd::apply、并行算法。

C++20

  • concepts(约束)coroutines(协程)ranges<=> 三向比较、consteval/constinit、span、formatjthread、以 Module 起步。

面试回答策略:C++11 名 + 2~3 个展开讲原理(移动、智能指针、lambda)→ 足够;C++20 至少知道 concepts/coroutines/ranges 三件套各一两句。

二、const vs constexpr

constconstexpr
求值期运行期(虽然整型常量表达式可折叠)编译期求值,必须常量表达式才能给
能力运行时 readonly编译期常量 + 可用于模板实参/数组大小/switch case
函数不能使普通函数变编译期constexpr 函数(C++11 简单、C++14 放宽,可普通语句)被要求时编译期求值,否则退化运行期
推断需要简单需自洽(变量须字面量等)
  • 优先用 constexpr 表达「编译期常量」语义;const 表达「运行期只读」即可。
  • C++17 if constexpr 编译期分支消除(模板里剪枝)。
  • C++20 consteval 强制编译期(不许运行时求值);constinit 保证静态初始化期常量。

三、default / delete(放大的声明控制)

  • = default:显式显式请求编译器生成默认实现。用途:想让析构/拷贝/移动保留默认行为但代码里又要声明它们(便于集中成类、或阻止编译期隐式删除、或继承 special member),或想恢复被「自定义其它 special member」抑制的默认函数。
  • = delete删除某个函数(调用即编译错)。用途:禁止拷贝、禁止特定重载、禁止从某些类型隐式转换等:
cpp
class NoCopy {
public:
    NoCopy() = default;
    NoCopy(const NoCopy&) = delete;            // 禁拷贝
    NoCopy& operator=(const NoCopy&) = delete;
};
void onlyInt(int);
template<typename T> void onlyInt(T) = delete; // 阻止其它类型实例调用

面试:为什么移动是 noexcept?为什么禁拷贝的类通常也禁赋值?——因为会破坏资源唯一性。default 与 delete 都能被继承影响,尤其=default 让你显式保留默认构造。

四、nullptr vs NULL(为什么 C++11 要 nullptr)

cpp
#define NULL 0        // 历史原因可能是 0 或 (void*)0
// C++ 精确重载痛点:
void f(int);
void f(char*);
f(NULL);   // ?? 调用 f(int)(NULL 是 int 0)—— 想调 char* 却调成 int
f(nullptr);// 明确调用 char* 重载 ✅
  • nullptr_t 类型,可隐式转任意指针bool,但不与整型混淆、不能当 int 0 用;消除指针/整型二义性,更安全。
  • 适用场景:函数重载、模板推导、比较、智能指针判空等。

五、range-for 与结构化绑定(速记)

cpp
for (const auto& x : vec)      // 只读遍历用 const auto&
for (auto x : vec)             // 拷贝(值太大浪费)谨慎
for (auto& x : vec)            // 修改
for (auto&& x : vec)           // 万能,透明(无拷贝)

auto [k, v] = m;               // 结构化绑定(C++17)
for (auto& [k,v] : m) { ... }  // 遍历 map,且修改 value

:range-for 底层是升级到迭代器;修改容器导致迭代器失效时对其遍历是 UB(如往 vector 里 push_back 过程中遍历)。

C++ 面试八股 · VitePress 版