C++ 智能指针详解:从原理到实践
在现代 C++ 开发中,智能指针是内存管理的核心工具,它们帮助我们避免内存泄漏和悬空指针问题。
为什么需要智能指针?
传统的裸指针存在诸多问题:
void problematic() {
int* ptr = new int(42);
// 如果这里抛出异常,内存泄漏!
doSomething();
delete ptr; // 可能永远执行不到
}
三种智能指针
unique_ptr:独占所有权
unique_ptr 确保同一时间只有一个指针拥有资源:
#include <memory>
auto ptr = std::make_unique<int>(42);
// std::unique_ptr<int> ptr2 = ptr; // 编译错误!
std::unique_ptr<int> ptr2 = std::move(ptr); // 转移所有权
使用场景:工厂函数返回值、类成员独占资源
shared_ptr:共享所有权
多个指针可共享同一资源,引用计数归零时自动释放:
auto sp1 = std::make_shared<std::string>("Hello");
auto sp2 = sp1; // 引用计数 = 2
std::cout << sp1.use_count() << std::endl; // 输出: 2
注意:避免循环引用!
weak_ptr:打破循环引用
weak_ptr 是 shared_ptr 的观察者,不增加引用计数:
class Node {
public:
std::shared_ptr<Node> next;
std::weak_ptr<Node> prev; // 使用 weak_ptr 避免循环引用
};
性能对比
| 特性 | unique_ptr | shared_ptr | weak_ptr |
|---|---|---|---|
| 开销 | 零开销 | 引用计数 | 引用计数 |
| 拷贝 | 不可拷贝 | 可拷贝 | 可拷贝 |
| 线程安全 | 否 | 计数安全 | 计数安全 |
最佳实践
优先使用 make_unique/make_shared
// 推荐 auto ptr = std::make_unique<Widget>(); // 不推荐 std::unique_ptr<Widget> ptr(new Widget());函数参数传递
void process(Widget* w); // 不转移所有权 void consume(std::unique_ptr<Widget> w); // 转移所有权
总结
智能指针是现代 C++ 的基石。合理选择 unique_ptr、shared_ptr 和 weak_ptr,能让代码更安全、更易维护。