C++ 智能指针详解: std::unique_ptr 和 std::shared_ptr
C++11引入了智能指针,它们是管理动态分配内存的强大工具。本文将详细介绍两种最常用的智能指针: std::unique_ptr
和 std::shared_ptr
。
std::unique_ptr
概述
std::unique_ptr
是一种独占所有权的智能指针。它确保一个对象只能被一个 unique_ptr
所拥有,这意味着不能复制 unique_ptr
,只能移动它。
主要特性
- 独占所有权: 一个
unique_ptr
不能被复制,只能被移动。 - 自动释放: 当
unique_ptr
离开作用域时,它所管理的对象会被自动删除。 - 零开销: 在大多数操作中,
unique_ptr
与原始指针的性能相当。 - 自定义删除器: 可以指定自定义的删除方式。
示例代码
#include <iostream>
#include <memory>
class MyClass {
public:
MyClass() { std::cout << "MyClass constructed\n"; }
~MyClass() { std::cout << "MyClass destructed\n"; }
void doSomething() { std::cout << "Doing something\n"; }
};
int main() {
// 创建unique_ptr
std::unique_ptr<MyClass> ptr1 = std::make_unique<MyClass>();
// 使用->访问成员
ptr1->doSomething();
// 无法复制unique_ptr
// std::unique_ptr<MyClass> ptr2 = ptr1; // 编译错误
// 可以移动unique_ptr
std::unique_ptr<MyClass> ptr2 = std::move(ptr1);
// ptr1现在为空
if (ptr1 == nullptr) {
std::cout << "ptr1 is null\n";
}
// ptr2现在拥有对象
ptr2->doSomething();
// 离开作用域时,ptr2自动删除对象
}
std::shared_ptr
概述
std::shared_ptr
是一种共享所有权的智能指针。多个 shared_ptr
可以指向同一个对象,对象的内存会在最后一个引用被销毁时释放。
主要特性
- 共享所有权: 多个
shared_ptr
可以指向同一个对象。 - 引用计数: 内部维护一个引用计数,当计数降为0时删除对象。
- 线程安全: 引用计数的增减是原子操作,但对象本身的访问不是线程安全的。
- 可以从 this 指针创建: 可以安全地从一个对象的成员函数中创建指向 this 的
shared_ptr
。
示例代码
#include <iostream>
#include <memory>
class SharedClass : public std::enable_shared_from_this<SharedClass> {
public:
SharedClass() { std::cout << "SharedClass constructed\n"; }
~SharedClass() { std::cout << "SharedClass destructed\n"; }
std::shared_ptr<SharedClass> getShared() {
return shared_from_this();
}
};
int main() {
// 创建shared_ptr
auto ptr1 = std::make_shared<SharedClass>();
{
// 创建另一个指向同一对象的shared_ptr
std::shared_ptr<SharedClass> ptr2 = ptr1;
std::cout << "使用计数: " << ptr1.use_count() << std::endl; // 输出 2
// 从对象内部获取shared_ptr
auto ptr3 = ptr1->getShared();
std::cout << "使用计数: " << ptr1.use_count() << std::endl; // 输出 3
// ptr2和ptr3离开作用域,但对象不会被删除
}
std::cout << "使用计数: " << ptr1.use_count() << std::endl; // 输出 1
// ptr1离开作用域,对象被删除
}
比较 unique_ptr 和 shared_ptr
特性 | std::unique_ptr | std::shared_ptr |
---|---|---|
所有权 | 独占 | 共享 |
复制 | 不允许 | 允许 |
移动 | 允许 | 允许 |
引用计数 | 无 | 有 |
性能开销 | 几乎为零 | 有一定开销 |
内存使用 | 与原始指针相同 | 额外内存用于控制块 |
线程安全 | 不适用 | 引用计数操作是安全的 |
循环引用 | 不会发生 | 可能发生,需要注意 |
最佳实践
- 优先使用
std::unique_ptr
,除非确实需要共享所有权。 - 使用
std::make_unique
和std::make_shared
来创建智能指针。 - 避免使用裸指针,尽可能使用智能指针。
- 注意避免
std::shared_ptr
的循环引用问题,必要时使用std::weak_ptr
。 - 在类的公共接口中返回
std::unique_ptr
来转移所有权。 - 在需要共享但不参与所有权的场景中使用
std::weak_ptr
。
std::unique_ptr
和 std::shared_ptr
是C++中管理动态内存的强大工具。正确使用这些智能指针可以大大减少内存泄漏的风险,提高代码的安全性和可维护性。理解它们的特性和适用场景对于编写高质量的C++程序至关重要。