【问题标题】:Best way to hold on to a shared_ptr returned from a factory Create method保持从工厂 Create 方法返回的 shared_ptr 的最佳方法
【发布时间】:2014-07-24 13:22:55
【问题描述】:

我有一个作用域保护对象工厂,它返回一个 shared_ptr 给我想在作用域期间保留的保护。

工厂的Create方法声明为:

virtual boost::shared_ptr<GenericGuard> Create() const = 0;

我的问题是——写起来更好吗:

boost::shared_ptr<SelectorGenericGuard> guard = factory->Create();

或:

const boost::shared_ptr<SelectorGenericGuard>& guard = factory->Create();

第一个版本可以/可能/将创建shared_ptr 的副本,因此可以/可能/将导致额外的引用计数器增量 - 第二个版本显然可读性较差,我无法确定我的“默认”应该是 - 所有被认为可读性的东西通常是我最喜欢的,我想听听其他人的想法。

或者我应该在这里使用auto_ptr(将来是unique_ptr)并免费使用第一个更易读的表格吗? (这里唯一的缺点是使用auto_ptr ;))

【问题讨论】:

  • 在复制初始化期间,没有任何理智的实现会真正执行复制。两者在性能上是相当的。当然,后者会阻止您修改值,尤其是您将无法重置指针以提前解除警卫。

标签: c++ boost shared-ptr factory


【解决方案1】:

很可能两者都会产生完全相同的代码:

  1. 这会将返回值绑定到常量引用。
    没有优化的理论开销:一个引用更多的内存,访问的额外间接。
    实际上:在 as-if 规则下优化掉开销

    const boost::shared_ptr<SelectorGenericGuard>& guard = factory->Create();
    
  2. 这通过初始化一个变量来保存返回值。
    没有优化的理论开销:一个动作和一个 dtor
    实际上:根据复制省略规则(as-if 规则除外)优化掉开销
    增加的危险:只有在类型完全匹配时才能进行优化。

    boost::shared_ptr<SelectorGenericGuard> guard = factory->Create();
    
  3. 与 2 相同,但不可能出现类型不匹配且更短(我的首选):

    auto guard = factory->Create();
    

关于auto_ptr:
总是喜欢unique_ptr
如果不能,请注意陷阱: 将语义移到写入副本的位置,从而导致标准算法和容器失败。考虑定义自己的不可复制版本,并在需要的任何地方进行明确的移动。将其保留在 ABI 之外,以便以后替换:函数参数(和异常类型)。

关于unique_ptr:如果可以的话,unique_ptrshared_ptr 更可取,因为可以减少(说:否)开销。

【讨论】:

  • 谢谢 - 我希望我可以使用自动... :)
  • 你有decltype吗?还是编译器太旧?
  • 编译器太旧,可能会保持这种状态一段时间。
  • 至于您的编辑 - 看来您同意 shared_ptr 现在是比 auto_ptr 更好的选择,对吧?
  • 不,由于开销,更喜欢auto_ptr 而不是shared_ptr。或者,可以使用自定义 scoped_ptr,它是 unique_ptr,没有移动语义,并尽可能将其换掉(确保您能够在不破坏二进制兼容性的情况下随时替换它)。因此,永远不要将自制的东西用作异常类型或函数参数,并确保它与 unique_ptr 具有相同的布局。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-06
  • 2014-09-24
  • 2018-08-31
  • 2013-06-11
  • 1970-01-01
  • 2012-01-29
相关资源
最近更新 更多