【C++】C++11 知识点梳理(中)

发布时间:2026/7/8 20:47:22
【C++】C++11 知识点梳理(中) 一、智能指针C11 引入了智能指针用于自动管理动态分配的内存避免内存泄漏。1.1 unique_ptrunique_ptr独占所指向的对象不支持拷贝但支持移动语义。#include memory #include iostream int main() { // 创建一个 unique_ptr管理一个 int std::unique_ptrint p1(new int(42)); std::cout *p1 std::endl; // 输出 42 // 移动语义转移所有权 std::unique_ptrlt;intgt; p2 std::move(p1); // 此时 p1 为空p2 拥有对象 if (!p1) { std::cout lt;lt; p1 is now empty lt;lt; std::endl; } // 使用 make_unique (C14 引入但常与 C11 一起讨论) auto p3 std::make_uniquelt;intgt;(100); return 0; }1.2 shared_ptrshared_ptr通过引用计数实现共享所有权当最后一个shared_ptr被销毁时对象被释放。#include memory #include iostream class MyClass { public: MyClass() { std::cout MyClass constructed\n; } ~MyClass() { std::cout MyClass destroyed\n; } void sayHello() { std::cout Hello from MyClass\n; } }; int main() { std::shared_ptrMyClass sp1(new MyClass()); { std::shared_ptrMyClass sp2 sp1; // 引用计数1 sp2-sayHello(); } // sp2 离开作用域引用计数-1 // sp1 仍然有效 sp1-sayHello(); return 0; } // sp1 离开作用域引用计数归零对象被销毁1.3 weak_ptrweak_ptr是shared_ptr的弱引用不增加引用计数用于解决循环引用问题。#include memory #include iostream struct Node { std::shared_ptrNode next; std::weak_ptrNode prev; // 使用 weak_ptr 避免循环引用 int value; Node(int v) : value(v) {} }; int main() { auto node1 std::make_sharedNode(1); auto node2 std::make_sharedNode(2); node1-gt;next node2; node2-gt;prev node1; // 弱引用不会增加 node1 的引用计数 // 通过 weak_ptr 访问对象 if (auto sp node2-gt;prev.lock()) { std::cout lt;lt; Previous node value: lt;lt; sp-gt;value lt;lt; std::endl; } else { std::cout lt;lt; Object has been destroyed\n; } return 0; }二、右值引用与移动语义右值引用T和移动语义是 C11 性能优化的核心允许资源如动态内存的“转移”而非“拷贝”。2.1 左值、右值与右值引用左值 (lvalue)有名字、有地址的表达式。右值 (rvalue)临时对象、字面量除字符串字面量、返回非引用的函数调用。右值引用绑定到右值的引用用声明。int a 10; // a 是左值 int lref a; // 左值引用 // int rref 20; // 错误不能将左值引用绑定到右值 int rref 20; // 右值引用绑定到字面量 int rref2 std::move(a); // 通过 std::move 将左值转换为右值引用2.2 移动构造函数与移动赋值运算符定义了移动语义的类可以高效转移资源。#include utility // for std::move #include cstring class String { public: char* data; size_t length; // 构造函数 String(const char* str) { length strlen(str); data new char[length 1]; strcpy(data, str); std::cout lt;lt; Constructor\n; } // 拷贝构造函数深拷贝 String(const Stringamp; other) { length other.length; data new char[length 1]; strcpy(data, other.data); std::cout lt;lt; Copy Constructor\n; } // 移动构造函数资源转移 String(Stringamp;amp; other) noexcept { data other.data; length other.length; other.data nullptr; // 置空原指针防止重复释放 other.length 0; std::cout lt;lt; Move Constructor\n; } // 析构函数 ~String() { delete[] data; } }; int main() { String s1(Hello); String s2 s1; // 调用拷贝构造函数 String s3 std::move(s1); // 调用移动构造函数s1 的资源被转移 return 0; }2.3 std::move 与 std::forwardstd::move无条件将参数转换为右值引用用于启动移动语义。std::forward完美转发保持参数原有的值类别左值/右值用于模板编程。#include utility #include iostream void process(int x) { std::cout lvalue: x std::endl; } void process(int x) { std::cout rvalue: x std::endl; } templatetypename T void relay(T arg) { // 使用 std::forward 保持 arg 的原始值类别 process(std::forwardT(arg)); } int main() { int a 10; relay(a); // 传递左值调用 process(int) relay(20); // 传递右值调用 process(int) return 0; }三、Lambda 表达式Lambda 表达式提供了一种简洁的定义匿名函数对象的方式。3.1 基本语法[capture] (parameters) - return_type { body }capture捕获列表指定哪些外部变量在 lambda 体内可用。parameters参数列表可选。return_type返回类型可选可自动推导。body函数体。3.2 捕获方式#include iostream #include vector #include algorithm int main() { int x 10; int y 20; // 值捕获 auto lambda1 [x]() { return x; }; // 捕获 x 的副本 // 引用捕获 auto lambda2 [amp;y]() { return y; }; // 捕获 y 的引用 // 隐式值捕获所有变量 auto lambda3 []() { return x y; }; // 捕获所有外部变量的副本 // 隐式引用捕获所有变量 auto lambda4 [amp;]() { return x y; }; // 捕获所有外部变量的引用 // 混合捕获 auto lambda5 [x, amp;y]() { return x y; }; // x 值捕获y 引用捕获 std::cout lt;lt; lambda1() lt;lt; std::endl; // 10 std::cout lt;lt; lambda2() lt;lt; std::endl; // 21, y 变为 21 std::cout lt;lt; y lt;lt; std::endl; // 21 // 在算法中使用 lambda std::vectorlt;intgt; vec {1, 2, 3, 4, 5}; int threshold 3; // 捕获 threshold 用于比较 auto it std::find_if(vec.begin(), vec.end(), [threshold](int val) { return val gt; threshold; }); if (it ! vec.end()) { std::cout lt;lt; First element gt; lt;lt; threshold lt;lt; is lt;lt; *it lt;lt; std::endl; } return 0; }3.3 泛型 Lambda (C14) 与 mutable#include iostream int main() { // mutable 允许修改按值捕获的变量修改的是副本 int count 0; auto counter count mutable { return count; // 修改的是捕获的副本不影响外部的 count }; std::cout counter() std::endl; // 1 std::cout counter() std::endl; // 2 std::cout Original count: count std::endl; // 0 // C14 泛型 Lambda使用 auto 参数 auto add [](auto a, auto b) { return a b; }; std::cout lt;lt; add(1, 2) lt;lt; std::endl; // 3 std::cout lt;lt; add(1.5, 2.3) lt;lt; std::endl; // 3.8 return 0; }