c++11智能指针

c++11中引入了3个智能指针类型:

  1. std::unique_ptr<T> :独占资源所有权的指针
  2. std::shared_ptr<T> :共享资源所有权的指针
  3. std::weak_ptr<T> : 共享资源的观察者,需要和std::shared_ptr一起使用

std::unique_ptr

  当我们独占资源的所有权的时候,可以使用 std::unique_ptr 对资源进行管理——离开 unique_ptr 对象的作用域时,会自动释放资源。这是很基本的 RAII 思想。

  需要注意的是:std::unique_ptr是move-only的

{
    std::unique_ptr<int> uptr = std::make_unique<int>(200);
    std::unique_ptr<int> uptr1 = uptr;  // 编译错误,std::unique_ptr<T> 是 move-only 的

    std::unique_ptr<int> uptr2 = std::move(uptr);
    assert(uptr == nullptr);
}

   std::unique_ptr可以指向一个数组以及自定义deleter

std::shared_ptr

   对引用资源进做引用计数,当引用计数为0的时候,自动释放资源。

{
    std::shared_ptr<int> sptr = std::make_shared<int>(200);
    assert(sptr.use_count() == 1);  // 此时引用计数为 1
    {   
        std::shared_ptr<int> sptr1 = sptr;
        assert(sptr.get() == sptr1.get());
        assert(sptr.use_count() == 2);   // sptr 和 sptr1 共享资源,引用计数为 2
    }   
    assert(sptr.use_count() == 1);   // sptr1 已经释放
}
// use_count 为 0 时自动释放内存

  std::shared_ptr也可以指向一个数组(c++20)以及自定义deleter

std::weak_ptr

 

  std::weak_ptr 要与 std::shared_ptr 一起使用。 一个 std::weak_ptr 对象看做是 std::shared_ptr 对象管理的资源的观察者,它不影响共享资源的生命周期:

 

  1. 如果需要使用 weak_ptr 正在观察的资源,可以将 weak_ptr 提升为 shared_ptr。
  2. 当 shared_ptr 管理的资源被释放时,weak_ptr 会自动变成 nullptr。
void Observe(std::weak_ptr<int> wptr) {
    if (auto sptr = wptr.lock()) {
        std::cout << "value: " << *sptr << std::endl;
    } else {
        std::cout << "wptr lock fail" << std::endl;
    }
}

std::weak_ptr<int> wptr;
{
    auto sptr = std::make_shared<int>(111);
    wptr = sptr;
    Observe(wptr);  // sptr 指向的资源没被释放,wptr 可以成功提升为 shared_ptr
}
Observe(wptr);  // sptr 指向的资源已被释放,wptr 无法提升为 shared_ptr

  作为资源的观察者,内部应该有一些比较实用的功能,但是自己并没有使用过。至于为什么记录这个智能指针,是因为自己的一个需求间接的使用到了这个。

  

  一个很常见的功能,就是类的成员函数内部获取指向自身(this)的 shared_ptr,看看下面这个例子有没有问题

class Foo {
 public:
  std::shared_ptr<Foo> GetSPtr() {
    return std::shared_ptr<Foo>(this);
  }
};

auto sptr1 = std::make_shared<Foo>();
assert(sptr1.use_count() == 1);
auto sptr2 = sptr1->GetSPtr();
assert(sptr1.use_count() == 1);
assert(sptr2.use_count() == 1);

  上面的代码其实会生成两个独立的 shared_ptr,他们的控制块是独立的,最终导致一个 Foo 对象会被 delete 两次。第二次会报错。

  成员函数获取 this 的 shared_ptr 的正确的做法是继承 std::enable_shared_from_this

class Bar : public std::enable_shared_from_this<Bar> {
 public:
  std::shared_ptr<Bar> GetSPtr() {
    return shared_from_this();
  }
};

auto sptr1 = std::make_shared<Bar>();
assert(sptr1.use_count() == 1);
auto sptr2 = sptr1->GetSPtr();
assert(sptr1.use_count() == 2);
assert(sptr2.use_count() == 2);

  一般情况下,继承了 std::enable_shared_from_this 的子类,成员变量中增加了一个指向 this 的 weak_ptr。这个 weak_ptr 在第一次创建 shared_ptr 的时候会被初始化,指向 this。

  但是似乎继承了 std::enable_shared_from_this 的类都被强制必须通过 shared_ptr 进行管理

auto b = new Bar;
auto sptr = b->shared_from_this();

 

智能指针,本质上是对资源所有权和生命周期管理的抽象

  1. 当资源是被独占时,使用 std::unique_ptr 对资源进行管理。
  2. 当资源会被共享时,使用 std::shared_ptr 对资源进行管理。
  3. 使用 std::weak_ptr 作为 std::shared_ptr 管理对象的观察者。
  4. 通过继承 std::enable_shared_from_this 来获取 this 的 std::shared_ptr 对象。

转载:https://zhuanlan.zhihu.com/p/150555165

posted @ 2022-07-30 17:03  那么强大  阅读(331)  评论(0编辑  收藏  举报