我的理解如下,
多个对象使用shared_ptr不能确定谁是最后一个指针,它在声明指针时更不可能知道指针指向的实际类型,所以这里调用实际类型的析构就是shared_ptr必须解决的问题。
unique_ptr则相反,它拥有指针(一般是它自己创建,少部分调用创建代码,总之是知道如何创建这个指针)它声明时就知道这个指针一定是它释放(或者交给知道如何释放代码),所以声明时知道实际类型。
场景上决定,unique_ptr不需要解决shared_ptr的问题。
网站首页 文章专栏 请教shared_ptr在析构时的奇怪表现。
我的理解如下,
多个对象使用shared_ptr不能确定谁是最后一个指针,它在声明指针时更不可能知道指针指向的实际类型,所以这里调用实际类型的析构就是shared_ptr必须解决的问题。
unique_ptr则相反,它拥有指针(一般是它自己创建,少部分调用创建代码,总之是知道如何创建这个指针)它声明时就知道这个指针一定是它释放(或者交给知道如何释放代码),所以声明时知道实际类型。
场景上决定,unique_ptr不需要解决shared_ptr的问题。
std::shared_ptr<Base> p = std::make_shared<Inherit>();
这句,实际是
make_shared创建了一个std::shared_ptr<Inherit>类型的对象,然后copy构造或者copy assignment给外面的p,从而p对象内hold的raw pointer是Inherit类型。所以不知道该是特性还是巧合,应该不是bug。
我个人认为这中uniqueptr和sharedptr的奇怪不同是因为标准库的设计目的。
uniqueptr 的性能应该媲美原始指针,因此有很多的事情需要在编译期确定。
sharedptr 因为有引用计数等实现方法,性能上完全不能媲美原始指针。那倒不如将sharedptr中的大量功能设计成不依赖编译期完全确定。可能你会觉得“sharedptr这样设计不就性能更低了吗?” 但 sharedptr就是用起来无脑简单的。
设计目的的不同 ,让两种共享指针上 做析构这件事时 有了些许差异。
purecpp
一个很酷的modern c++开源社区
purecpp社区自2015年创办以来,以“Newer is Better”为理念,相信新技术可以改变世界,一直致力于现代C++研究、应用和技术创新,期望通过现代C++的技术创新来提高企业生产力和效率。
社区坚持只发表原创技术文章,已经累计发表了一千多篇原创C++技术文章;
组织了十几场的C++沙龙和C++大会,有力地促进了国内外C++开发者之间的技术交流;
开源了十几个现代C++项目,被近百家公司所使用,有力地推动了现代C++在企业中的应用。
期待更多的C++爱好者能参与到社区C++社区的建设中来,一起为现代C++开源项目添砖加瓦,一起完善C++基础设施和生态圈。
微信公众号:purecpp, 社区邮箱: purecpp@163.com
Hi lijixiang,
你这个问题问得很好。
原因是这样的:shared_ptr的构造函数是一个模板函数,shared_ptr会记住这个指针类型即你例子中的Base*类型,shared_ptr析构的时候会调用delete Base*的指针,而不管这个Base是否有虚的析构函数。
简言之,在share_ptr模板类型和实际类型的析构函数都会被调用到。而unique_ptr则不会去调用模板类型的析构函数。
也许你还想进一步了解为什么unique_ptr不会去调用基类的析构函数,这是因为shared_ptr和unique_ptr的实现方式不同导致的,shared_ptr中的模板参数T允许是一个incomplete type,最终是需要一个完整类型的,通过在最后删除的时候去调用这个incomplete type的析构函数来保证类型的完整性;
而unique_ptr一开始就要求这个模板类型必须是complete type,所以也就不需要去调用模板参数类型的析构函数了。