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[使用裸指针或无需指针]