一、智能指针

C++11 引入了智能指针,用于自动管理动态分配的内存,避免内存泄漏。

1.1 unique_ptr

unique_ptr 独占所指向的对象,不支持拷贝,但支持移动语义。

#include <memory>
#include <iostream>
int main() {
// 创建一个 unique_ptr,管理一个 int
std::unique_ptr<int> p1(new int(42));
std::cout << *p1 << std::endl; // 输出 42
// 移动语义转移所有权
std::unique_ptr&lt;int&gt; p2 = std::move(p1);
// 此时 p1 为空,p2 拥有对象
if (!p1) {
    std::cout &lt;&lt; "p1 is now empty" &lt;&lt; std::endl;
}
// 使用 make_unique (C++14 引入,但常与 C++11 一起讨论)
auto p3 = std::make_unique&lt;int&gt;(100);
return 0;
}

1.2 shared_ptr

shared_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_ptr<MyClass> sp1(new MyClass());
{
std::shared_ptr<MyClass> sp2 = sp1; // 引用计数+1
sp2->sayHello();
} // sp2 离开作用域,引用计数-1
// sp1 仍然有效
sp1->sayHello();
return 0;
} // sp1 离开作用域,引用计数归零,对象被销毁

1.3 weak_ptr

weak_ptrshared_ptr 的弱引用,不增加引用计数,用于解决循环引用问题。

#include <memory>
#include <iostream>
struct Node {
std::shared_ptr<Node> next;
std::weak_ptr<Node> prev; // 使用 weak_ptr 避免循环引用
int value;
Node(int v) : value(v) {}
};
int main() {
auto node1 = std::make_shared<Node>(1);
auto node2 = std::make_shared<Node>(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&&)和移动语义是 C++11 性能优化的核心,允许资源(如动态内存)的“转移”而非“拷贝”。

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 String&amp; other) {
length = other.length;
data = new char[length + 1];
strcpy(data, other.data);
std::cout &lt;&lt; "Copy Constructor\n";
}
// 移动构造函数(资源转移)
String(String&amp;&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::forward

  • std::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;
}
template<typename T>
void relay(T&& arg) {
// 使用 std::forward 保持 arg 的原始值类别
process(std::forward<T>(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::vector&lt;int&gt; 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 (C++14) 与 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
// C++14 泛型 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;
}
Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐