【问题标题】:Are there any downsides with using make_shared to create a shared_ptr使用 make_shared 创建 shared_ptr 有什么缺点吗
【发布时间】:2011-01-09 23:52:48
【问题描述】:

使用make_shared<T>() 代替shared_ptr<T>(new T) 有什么缺点吗?

Boost documentation 状态

收到了多次来自 用户的工厂功能, 创建给定类型的对象并 返回一个 shared_ptr 给它。除了 方便和风格,这样的功能 也是异常安全的 相当快,因为​​它可以使用 一个单一的分配为 对象及其对应的控件 块,消除显着 shared_ptr 构造的一部分 高架。这消除了其中一个 主要效率投诉 shared_ptr.

【问题讨论】:

  • 有人可能想知道,关于 shared_ptr 的其他主要效率问题是什么?
  • 异常安全是std::make_shared 的一个非常强大的资产。尽可能尝试使用它。
  • @ViktorSehr Mutex 在主要复制shared_ptr 时锁定引用计数器:)
  • @Drax:啊,所以它们是线程安全的?不知道
  • @Drax 不要介意问号顺便说一句,我可以 google :)

标签: c++ boost shared-ptr


【解决方案1】:

除了@deft_code 给出的点之外,还有一个更弱的点:

  • 如果你使用weak_ptrs,它在给定对象的所有shared_ptrs 都死后仍然存在,那么这个对象的内存将与控制块一起存在于内存中,直到最后一个weak_ptr 死掉。换句话说,对象被销毁但直到最后一个 weak_ptr 被销毁时才被释放。

【讨论】:

  • 不使用make_shared也是如此。唯一的区别是控制块将位于单独分配的内存块中。
  • @Mike:当然不会——通常情况下,如果对象没有 shared_ptrs,只有weak_ptrs,那么会立即删除该对象。我不知道控制块是否仍然存在,我会相信你的话。使用 make_shared,控制块和对象共存一个分配,因此如果其中一个的内存仍然存在,那么两者都可以(尽管我猜对象已被破坏,只是内存没有释放?)。
  • 呃,是的。对不起。当我写这篇文章时,我一定是在用我的另一个大脑。
【解决方案2】:

我知道至少有两个。

  • 您必须控制分配。真的不是一个大的,但一些较旧的 api 喜欢返回必须删除的指针。
  • 没有自定义删除器。我不知道为什么不支持,但事实并非如此。这意味着您的共享指针必须使用普通删除器。

相当弱的地方。所以尽量总是使用 make_shared。

【讨论】:

  • 没有自定义删除器,因为只有 make_shared 自己知道如何删除对象。
  • 自定义删除器用于做一些有趣的技巧,不仅限于删除,这就是 deft_code 提到它的原因。
  • 如果您可以添加自定义删除器,那么您也应该具有自定义分配器的能力;假设它会使界面过于复杂。
  • @MikeSeymour:从shared_ptr 的角度来看,是的,它需要有一个由make_shared() 提供的自定义删除器,但提供@ 的调用者是可能的,也许有用987654324@ 能够运行从make_shared() 自己的自定义删除器内部运行的自定义“子删除器”。
  • 我的意思是它看起来像这样:template<class T, class Allocator, class Deleter, class... Args> shared_ptr<T> make_shared2(Allocator a, Deleter d, Args... args); 是的,它可以提供,但它不是很漂亮。
【解决方案3】:

来自http://www.codesynthesis.com/~boris/blog/2010/05/24/smart-pointers-in-boost-tr1-cxx-x0/

make_shared() 实现的另一个缺点是目标代码大小的增加。由于这种优化的实现方式,对于您使用 make_shared() 使用的每种对象类型,都会实例化一个额外的虚拟表以及一组虚拟函数。

【讨论】:

  • 随着编译器的进步,这种情况是否会持续下去?
【解决方案4】:

另外,make_shared 与工厂模式不兼容。这是因为在您的工厂函数中调用make_shared 调用了库代码,而库代码又调用了它无法访问的new因为它无法调用类的私有构造函数(如果您正确遵循工厂模式,构造函数应该是私有的)。

【讨论】:

    【解决方案5】:

    使用 make shared,您无法指定所持有对象的 allocationdeallocation 将如何完成。

    如果需要,请改用std::allocate_shared<T>

    std::vector<std::shared_ptr<std::string>> avec; 
    std::allocator<std::string> aAllocator;
    avec.push_back(std::allocate_shared<std::string>(aAllocator,"hi there!"));
    

    注意,vector不需要知道allocator!

    要制作自定义分配器,请查看此处https://stackoverflow.com/a/542339/1149664

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-04-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-09-27
      相关资源
      最近更新 更多