智能指针

Tags
指针
智能指针能够自动判别指针是否离开其生命周期,自动回收资源,防止资源泄露。
智能指针有四种:unique_ptrshared_ptrweak_prtauto_ptr (已废弃)

unique_ptr

void UseRawPointer() { // Using a raw pointer -- not recommended. Song* pSong = new Song(L"Nothing on You", L"Bruno Mars"); // Use pSong... // Don't forget to delete! delete pSong; } void UseSmartPointer(){ // Declare a smart pointer on stack and pass it the raw pointer. unique_ptr<Song> song2(new Song(L"Nothing on You", L"Bruno Mars")); // Use song2... wstring s = song2->duration_; //... } // song2 is deleted automatically here.
unique_ptr 智能指针,再离开其作用域的时候,释放对应的资源
std::unique_ptr<int> ptr1(new int); // 创建一个指向 int 的 unique_ptr // std::unique_ptr<int> ptr2 = ptr1; // 错误!不能复制 unique_ptr std::unique_ptr<int> ptr3 = std::move(ptr1); // 通过移动语义转移所有权
unique_ptr 智能指针变量不能拷贝给其他指针智能变量,类似 Rust 的所有权原则

shared_ptr

std::shared_ptr<int> ptr1 = std::make_shared<int>(42); // 创建一个指向 int 的 shared_ptr std::shared_ptr<int> ptr2 = ptr1; // 共享所有权
shared_ptr 是另一种智能指针,没有不能拷贝的限制,因此,它有一个计数器,其大小也是两个指针,一个指向变量地址,一个指向计数器地址。
shared_ptr 有循环计数的问题:
int main() { std::shared_ptr<A> a = std::make_shared<A>(); std::shared_ptr<B> b = std::make_shared<B>(); // 形成循环引用 a->bPtr = b; b->aPtr = a; return 0; }
在上面这种情况中,出现了指针指向自己的问题(如果环更大,就更难发现),导致对应地址的内存永远不会被释放。

weak_ptr

可以把 shared_ptr 拷贝给 weak_ptr 对象,但不参与计数器计数:
std::shared_ptr<int> sharedPtr = std::make_shared<int>(42); std::weak_ptr<int> weakPtr = sharedPtr;
然后通过 lock() 方法再从 weak_ptr 中获取 shared_ptr:
#include <memory> #include <iostream> int main() { std::shared_ptr<int> sharedPtr = std::make_shared<int>(42); std::weak_ptr<int> weakPtr = sharedPtr; // 创建一个指向 int 的 weak_ptr { // 开一个作用域,sharedPtr2 只在该作用域中使用 std::shared_ptr<int> sharedPtr2 = weakPtr.lock(); // 通过 lock() 获取 shared_ptr if (sharedPtr2) { // 使用 sharedPtr2,但不会增加引用计数 std::cout << "Value: " << *sharedPtr2 << std::endl; } else { std::cout << "Resource has been released." << std::endl; } } // sharedPtr2 超出作用域后,weakPtr 仍然有效,但引用计数未增加 return 0; }
如果原 shared_ptr 已经释放,那么返回的是空指针,否则可以获得原指针。weak_ptr 解决了使用 shared_ptr 出现的循环引用问题。

auto_ptr

⚠️
自C++11起,auto_ptr已被废弃(deprecated),推荐使用更安全和更灵活的std::unique_ptr代替。
auto_ptr的主要特点是,当它的所有权转移(通过赋值或传递)时,会自动删除原对象,从而避免了手动释放资源的问题。然而,auto_ptr存在以下主要问题,导致它的使用不推荐:
  1. 不支持数组:auto_ptr不支持管理动态分配的数组。尝试将数组对象传递给auto_ptr可能导致未定义行为。
  1. 不支持多态:auto_ptr的析构函数会调用delete操作符来释放对象,而不是delete[]。如果尝试使用auto_ptr管理一个基类指针指向一个派生类对象时,会导致不正确的内存释放。
  1. 拷贝语义问题:auto_ptr的拷贝语义是转移所有权,即当一个auto_ptr对象被复制时,原对象的所有权会转移到新对象,导致原对象为空(空指针)。这会导致潜在的资源释放问题,例如两个指针同时管理同一个对象时,会导致对象被重复删除。
 
参考资料: