Skip to content

现代 C++

C++11 常用特性

  • autodecltype 类型推导;
  • 基于范围的 for
  • Lambda 表达式与闭包;
  • 右值引用、移动语义、完美转发;
  • std::unique_ptrstd::shared_ptrstd::weak_ptr
  • nullptr 取代宏 NULL
  • constexprstatic_assert、强类型枚举 enum class
  • 并发库:std::thread、mutex、condition variable、atomic、future;
  • 统一初始化、委托构造、override/final

左值、右值与引用

现代 C++ 中不应仅按“有名字就是左值、临时就是右值”死记;更精确地说,表达式有 glvalue、prvalue、xvalue 等分类。但面试可先掌握:

  • **左值(lvalue)**通常表示有持久身份、可定位的对象;左值引用写作 T&
  • **右值(rvalue)**通常表示即将消亡的对象或纯值;右值引用写作 T&&,可绑定临时对象。
  • 命名的右值引用变量本身是左值表达式,要把它作为可移动对象继续传递,通常使用 std::move
cpp
std::string make_name();
const std::string& a = make_name(); // 临时对象生命周期延长到 a 的作用域结束
std::string&& b = make_name();      // 直接绑定时也延长生命周期

引用本身不是所有权。不要让引用或指针逃逸到被引用对象生命周期之外。

移动语义

复制大型资源(堆内存、文件句柄、网络连接等)可能昂贵。移动语义允许目标对象接管源对象的资源,而不是复制资源内容:

cpp
class Buffer {
public:
    Buffer(Buffer&& other) noexcept
        : data_(std::exchange(other.data_, nullptr)) {}
private:
    int* data_{};
};

移动构造函数和移动赋值接收 T&&。移动后源对象必须保持有效但状态未指定,不能假设它为空或不可用;可以重新赋值或销毁。std::move 不移动任何数据,它只是把表达式转换为可绑定右值引用的 xvalue,真正是否移动由被调用函数决定。

为移动操作标注 noexcept 很重要:例如 vector 扩容时,若移动可能抛异常,为保持强异常安全保证,容器可能选择拷贝而非移动。

Lambda 表达式

基本形式:

cpp
[capture](parameters) mutable noexcept -> return_type {
    // body
};

常见捕获:

cpp
int threshold = 10;

[threshold](int x) { return x > threshold; }; // 值捕获:副本
[&threshold](int x) { ++threshold; return x > threshold; }; // 引用捕获
[x = std::move(resource)] { /* 初始化捕获,转移资源 */ };
  • 默认 []operator()const;若需修改值捕获副本,使用 mutable
  • 引用捕获的 lambda 若被异步保存/返回,必须确保被引用对象仍存活,避免悬空引用。
  • Lambda 常用于 STL 算法、回调、异步任务和局部策略表达。无捕获 Lambda 可转换为函数指针;有捕获 Lambda 是闭包对象。

面试速答

移动语义的作用:针对临时对象或不再需要原资源的对象,把资源所有权转交给目标,避免深拷贝,提升容器扩容、函数返回和资源包装类型的性能。前提是正确维护源对象有效性、异常安全和所有权语义。

使用 Markdown 与 VitePress 构建