C++智能指针是现代C++中管理动态内存的重要工具,它们可以有效避免手动管理内存时可能出现的内存泄漏问题。本文将详细解析三种主要的智能指针类型:shared_ptr
、unique_ptr
和weak_ptr
,并探讨它们的使用场景及注意事项。
智能指针是一种用于自动管理动态分配内存的对象包装器。它通过引用计数或其他机制确保在对象不再被使用时自动释放内存。C++11引入了三种标准智能指针:
std::shared_ptr
:允许多个指针共享同一个对象。std::unique_ptr
:独占所指向的对象,不允许复制。std::weak_ptr
:不控制对象生命周期的弱引用,通常与shared_ptr
配合使用。std::shared_ptr
详解shared_ptr
通过引用计数来管理对象的生命周期。当最后一个shared_ptr
销毁或重置时,对象会被自动删除。
#include <iostream>
#include <memory>
int main() {
std::shared_ptr<int> sp1 = std::make_shared<int>(42); // 创建一个shared_ptr
std::cout << "sp1 use count: " << sp1.use_count() << "\n"; // 输出1
{
std::shared_ptr<int> sp2 = sp1; // 共享同一对象
std::cout << "sp1 use count: " << sp1.use_count() << "\n"; // 输出2
std::cout << "sp2 use count: " << sp2.use_count() << "\n"; // 输出2
}
std::cout << "sp1 use count: " << sp1.use_count() << "\n"; // 输出1
}
std::make_shared
创建shared_ptr
,比直接构造更高效且安全。struct Node {
std::shared_ptr<Node> next;
};
int main() {
std::shared_ptr<Node> n1 = std::make_shared<Node>();
std::shared_ptr<Node> n2 = std::make_shared<Node>();
n1->next = n2; // n1 引用 n2
n2->next = n1; // n2 引用 n1
// n1 和 n2 的引用计数都为2,导致无法释放
}
std::unique_ptr
详解unique_ptr
是一种独占所有权的智能指针,不能被复制,但可以通过移动语义转移所有权。
#include <iostream>
#include <memory>
int main() {
std::unique_ptr<int> up1 = std::make_unique<int>(42);
// std::unique_ptr<int> up2 = up1; // 错误:不能复制
std::unique_ptr<int> up2 = std::move(up1); // 移动所有权
if (!up1) {
std::cout << "up1 is null\n";
}
std::cout << *up2 << "\n"; // 输出42
}
unique_ptr
更为轻量且高效。unique_ptr
可以很好地管理动态分配的对象。std::weak_ptr
详解weak_ptr
是一个不控制对象生命周期的弱引用,通常与shared_ptr
配合使用。它可以解决循环引用问题。
#include <iostream>
#include <memory>
int main() {
std::shared_ptr<int> sp = std::make_shared<int>(42);
std::weak_ptr<int> wp = sp;
if (auto locked = wp.lock()) { // 尝试锁定
std::cout << *locked << "\n"; // 输出42
}
sp.reset(); // 释放shared_ptr
if (wp.expired()) { // 检查是否过期
std::cout << "weak_ptr has expired\n";
}
}
结合weak_ptr
和shared_ptr
可以避免循环引用问题。
struct Node {
std::shared_ptr<Node> next;
std::weak_ptr<Node> prev;
};
int main() {
std::shared_ptr<Node> n1 = std::make_shared<Node>();
std::shared_ptr<Node> n2 = std::make_shared<Node>();
n1->next = n2; // n1 引用 n2
n2->prev = n1; // n2 使用 weak_ptr 引用 n1
// 此时不会出现循环引用问题
}
智能指针 | 所有权 | 是否可复制 | 适用场景 |
---|---|---|---|
shared_ptr | 共享 | 可以 | 对象需要被多个指针共享时 |
unique_ptr | 独占 | 不可以 | 对象只需要一个所有者时 |
weak_ptr | 不控制生命周期 | 不可以 | 避免循环引用或延迟访问对象时 |
flowchart TD A[需要共享所有权?] -->|是| B[使用 shared_ptr] A -->|否| C[需要独占所有权?] C -->|是| D[使用 unique_ptr] C -->|否| E[使用裸指针或无需指针]