# 深入理解 C++ weak_ptr

面试高频指数:★★☆☆☆

# weak_ptr 是什么?

std::weak_ptr是C++11引入的一种智能指针,主要与std::shared_ptr配合使用。

它的主要作用是解决循环引用问题、观察std::shared_ptr对象而不影响引用计数,以及在需要时提供对底层资源的访问。

  1. 解决循环引用问题:当两个或多个std::shared_ptr对象互相引用时,会导致循环引用。这种情况下,这些对象的引用计数永远不会变为0,从而导致内存泄漏。

std::weak_ptr可以打破这种循环引用,因为它不会增加引用计数。只需要将其中一个对象的std::shared_ptr替换为std::weak_ptr,即可解决循环引用问题。

  1. 观察std::shared_ptr对象:std::weak_ptr可以用作观察者,监视std::shared_ptr对象的生命周期。它不会增加引用计数,因此不会影响资源的释放。

# 深入理解weak_ptr: 资源所有权问题

看到一篇对于 weak_ptr 讲解非常棒的文章,转到这里分享给大家:

原文链接: https://0cch.com/2022/10/31/some-tips-about-weakptr/ 作者:0cch

虽然智能指针进入C++11标准库已经有十多年了,但是我们对部分细节的理解还是比较局限。

std::weak_ptr为例,很多人的理解只是停留在避免std::shared_ptr出现相互引用,导致对象无法析构,内存无法释放的问题。

当然,并不是说这种用法有什么不对,恰恰相反,它是一个非常经典的使用场景。

但是std::weak_ptr的使用场景或者说它诞生的理念却不仅仅是这些,如果没有更加透彻理解std::weak_ptr,也很难合理的使用std::shared_ptr

std::weak_ptr从概念上,它是一个智能指针,相对于std::shared_ptr,它对于引用的对象是“弱引用”的关系。

简单来说,它并不“拥有”对象本身。

如果我们去类比生活中的场景,那么它可以是一个房地产中介。房地产中介并不拥有房子,但是我们有办法找到注册过的房产资源。

在客户想要买房子的时候,它起初并不知道房子是否已经卖出了,它需要找到房主询问后再答复客户。

std::weak_ptr做的事情几乎和房产中介是一模一样的。std::weak_ptr并不拥有对象,在另外一个std::shared_ptr想要拥有对象的时候,它并不能做决定,需要转化到一个std::shared_ptr后才能使用对象。所以std::weak_ptr只是一个“引路人”而已。

说了这么多,那么std::weak_ptr除了解决相互引用的问题,还能做什么?

答案是:一切应该不具有对象所有权,又想安全访问对象的情况。

还是以互相引用的情况为例,通常的场景是:一个公司类可以拥有员工,那么这些员工就使用std::shared_ptr维护。另外有时候我们希望员工也能找到他的公司,所以也是用std::shared_ptr维护,这个时候问题就出来了。但是实际情况是,员工并不拥有公司,所以应该用std::weak_ptr来维护对公司的指针。

再举一个例子:我们要使用异步方式执行一系列的Task,并且Task执行完毕后获取最后的结果。所以发起Task的一方和异步执行Task的一方都需要拥有Task。

但是有时候,我们还想去了解一个Task的执行状态,比如每10秒看看进度如何,这种时候也许我们会将Task放到一个链表中做监控。这里需要注意的是,这个监控链表并不应该拥有Task本身,放到链表中的Task的生命周期不应该被一个观察者修改。所以这个时候就需要用到std::weak_ptr来安全的访问Task对象了。

最后再来聊一个新手使用std::weak_ptr容易被坑的地方:对象资源竞争。

以下代码在多线程程序中是存在很大风险的,因为wp.expired()wp.lock()运行的期间对象可能被释放:

/ std::weak_ptr<SomeClass> wp{ sp };

if (!wp.expired()) {
    wp.lock()->DoSomething();
}

正确的做法是:

auto sp = wp.lock();
if (sp) {
    sp->DoSomething();
}

std::weak_ptrlock函数是一个原子操作。有趣的是,最开始的C++11标准是没有提到原子操作的,C++14标准才对这一点进行了补充,详细过程可以参考提案文档:LWG2316 (opens new window)

最新原创的文章都先发布在公众号,欢迎关注哦~,
扫描下方二维码回复「CS」可以获得我汇总整理的计算机学习资料~

编程指北图片
@2021-2024 编程指北 版权所有 粤ICP备2021169086号-2