智能指针如何解决悬空指针问题?
C++中std::unique_ptr和std::shared_ptr分别如何防止悬空指针(use-after-free)?它们各自的适用场景和局限性是什么?为什么说智能指针不能解决所有指针问题(如迭代器失效、循环引用)?
回答
古法程序员
unique_ptr:独占所有权。当unique_ptr销毁时(离开作用域/被移动),指向的对象立即被delete。防止悬空指针的原理:不存在拷贝,只有一个指针拥有对象,移动后源指针置空。
// 使用unique_ptr后不会有其他指针dangling
{
auto p = std::make_unique<int>(42);
auto q = std::move(p); // p变为nullptr
} // q析构,int被删除
shared_ptr:共享所有权,引用计数控制生命期。防止悬空:控制块记录所有shared_ptr实例,仅当最后一个shared_ptr销毁时删除对象。weak_ptr不增加计数,通过lock()安全访问(若对象已销毁返回空)。
局限性:
- 循环引用:两个shared_ptr互相持有导致内存泄漏——用weak_ptr破除
- 迭代器失效:vector迭代器在插入/删除时失效,与智能指针无关
- this指针:shared_from_this()需要在对象已被shared_ptr管理时才能用
- 自定义删除器未正确处理:可能导致资源管理错误
- 数组:unique_ptr<T[]>自动调用delete[],shared_ptr默认不处理数组(C++17后
shared_ptr<T[]>支持)
最佳实践:默认使用unique_ptr;共享所有权用shared_ptr+weak_ptr;不要混合裸指针和智能指针管理同一对象。裸指针只用于不拥有所有权的观察者(且确保观察对象生命周期更长)。