Item20 Use std::weak_ptr for std::shared_ptr like pointers that can dangle
2016-11-23 22:37
465 查看
原始指针有一个致命的问题就是无法探知生死,尽管你可以通过释放内存后设置为空来解决部分场景下存在的问题,但是这治标不治本,当有多个指针指向同一个内存资源的时候就无能无力了。那么在这篇文章中我将介绍一个大杀器
在上面的代码中
如果没有过期就进行提升,看似没有问题,但是这两步是非原子的,这就导致了线程安全的问题,不过幸好
上面基本都是在说
上图中的A和B的关系就是循环引用的关系,当A对象有一个shared_ptr指向B,B对象也有一个shared_ptr指向A,那么两者都持有对方的引用计数,导致对象无法析构。现实工程中存在这样的引用也是在情理之中的,那么使用weak_ptr就可以打破循环引用。又能通过weak_ptr访问对象,以满足工程上的需求。
std::weak_ptr,它可以探查生死,探查指针所指向的内存资源是否有效。陈硕有篇文章就专门介绍了std::weak_ptr,讲的很好,本文算是自己对
std::weak_ptr的理解。
auto spw = std::make_shared<Widget>(); std::weak_ptr<Widget> wpw(spw); spw = nullptr if (wpw.expired()) { std::cout << "Widget already destructor" << std::endl; }
在上面的代码中
swp = nullptr导致引用计数变为0,触发了
Widget的析构,此时使用
weak_ptr的
expired方法就可以探测这个对象是否已经析构了,这是
weak_ptr的典型用法。那么
weak_ptr除了严查生死外,能不能解引用来访问对象呢?答案是不,不过它提供了lock方法可以将
weak_ptr转换为
shared_ptr如下:
if (!wpw.expired()) { std::shared_ptr spw2(wpw); // 提升为shared_ptr,如果wpw过期,仍然要这样初始化会抛出 // std::bad_weak_ptr异常 }
如果没有过期就进行提升,看似没有问题,但是这两步是非原子的,这就导致了线程安全的问题,不过幸好
C++标准库的设计者考虑到了这个问题,提供了一个
lock函数可以直接提升为shared_ptr,如果过期了就返回
nullptr。
上面基本都是在说
weak_ptr本身,那么接下来谈论是
weak_ptr的用途,它是如何用在工程实践中。第一种就是用作缓存,实际工程中我们可能会
new很多对象,但是想根据某个key对其缓存,所以通常会将
key和对象使用
map保存起来。最简单的就是把对象的原始指针保存在map,很显然这不够好,因为不知道这个对象是否死了。如果存放
shared_ptr的确是可以保证对象是存活的(因为
map中本身就保存了一份,所以引用计数至少是1),那么这会导致另外一个问题就是对象的生存周期被拉长了,和
map一样长。但是使用
weak_ptr就不会存在这个问题,对象随时都会被回收不会延长对象的生命周期。
std::unordered_map<WidgetID, std::weak_ptr<const Widget> > cache;
weak_ptr的第二个用处就是解决循环引用的问题,先开看下面这张图,理解下什么是循环引用。
上图中的A和B的关系就是循环引用的关系,当A对象有一个shared_ptr指向B,B对象也有一个shared_ptr指向A,那么两者都持有对方的引用计数,导致对象无法析构。现实工程中存在这样的引用也是在情理之中的,那么使用weak_ptr就可以打破循环引用。又能通过weak_ptr访问对象,以满足工程上的需求。
相关文章推荐
- Item 20: 使用std::weak_ptr替换会造成指针悬挂的类std::shared_ptr指针
- Item 20: 使用std::weak_ptr替换会造成指针悬挂的类std::shared_ptr指针
- <Effective Modern C++>Item 18: Use std::unique_ptr for exclusive-ownership resource management.
- Item18 Use std::unique_ptr for exclusive-ownership resource management
- Effective Modern C++ 条款20 把std::weak_ptr当作类似std::shared_ptr的、可空悬的指针使用
- std::shared_ptr 和 std::weak_ptr的用法以及引用计数的循环引用问题
- std::shared_ptr 和 std::weak_ptr的用法以及引用计数的循环引用问题
- Item19 Use std::shared_ptr for shared-ownership resource management
- c++中的std::shared_ptr和std::weak_ptr
- error C2678 binary '<' : no operator found for map<std::string, shared_ptr<Foo>>
- std::shared_ptr 和 std::weak_ptr的用法以及引用计数的循环引用问题
- c++11 条款20:使用std::weak_ptr作为一个类似std::share_ptr但却能悬浮的指针
- 几种智能指针的比较(std::auto_ptr、boost::scoped_ptr、boost::shared_ptr、boost::weak_ptr)
- Item 40: Use Dynamic for Parameters That Receive Anonymous Types(Effective C#)
- Item21 Perfer std::make_unique and std::make_shared to direct use of new
- std::weak_ptr 每次 lock() 都会导致自身use_count自增一次
- std::shared_ptr 和 std::weak_ptr的用法以及引用计数的循环引用问题
- C++11 智能指针std::shared_ptr/std::unique_ptr/std::weak_ptr
- std::tr1::shared_ptr、std::tr1::weak_ptr及std::tr1::enable_shared_from_this
- ProgrammingError: You must not use 8-bit bytestrings unless you use a text_factory that can interpret 8-bit bytestrings (like text_factory = str). It is highly recommended that you instead just switch your application to Unicode strings