【问题标题】:Is moving shared_ptr better?移动 shared_ptr 更好吗?
【发布时间】:2016-11-19 15:18:03
【问题描述】:

我有办法

structA
{
     shared_ptr<B> m_b;

     // 2 options to set m_b

     void setB1(shared_ptr<B> b)
     {
         m_b = move(b);
     }

     void setB2(shared_ptr<B> const&b)
     {
         m_b = b;
     }
};

哪个性能更好?如果我将setB1 称为setB1(b) 而不是setB1(move(b)),它们都会复制。我更关心它在 b 可以被无效并且 b 只能被复制时的性能。

我在 VC2015 上的测试答案:

setB1setB2

  • 左值 b 增加 30%
  • 右值 b 降低 8%

【问题讨论】:

  • 大概您打算将m_b 的类型设置为shared_ptr&lt;B&gt; 而不仅仅是B
  • 这两个做不同的事情:复制创建新的shared_ptr 指向同一个东西,移动会使原来的shared_ptr 无效。您应该考虑自己的目标,而不是绩效。
  • @GingerPlusPlus :移动会使本地 b 对象无效,该对象在函数退出时被销毁。
  • @GingerPlusPlus 如果我将setB1 称为setB1(b) 而不是setB1(move(b)),他们都会进行复制。我更关心它的性能,例如当 b 可以无效时。

标签: c++ c++11 std shared-ptr


【解决方案1】:

这里的性能差异会很小。

其中一个在参数中创建一个副本,然后移出它。

other 引用参数中的外部副本,并从中复制出来。

如果您使用共享 ptr 创建函数(如 make_shared)调用第一个函数,您将获得 1 次移动和 0 次复制和 1 次微不足道的破坏。对于第二个,您获得 0 次移动和 1 次复制和 1 次非平凡破坏。

如果您调用第一个只是按值传递一些随机共享 ptr,您将获得 1 个副本、1 个移动和 1 个琐碎的破坏。在第二个中,您获得 1 个副本和 0 个移动。

复制共享 ptr 是一个原子增量。琐碎的破坏是一个分支。非平凡是一个分支和一个原子减量。移动共享 ptr 只是设置一些指针。

【讨论】:

  • 我投反对票的原因是“性能差异将很小”这一不受支持的断言。我已经看到 shared_ptr 在某些情况下会增加大量开销,主要是因为复制 shared_ptr 会导致原子操作会影响单线程和多线程性能。 OP 的小型性能测试反映了这一点。如果可能,移动 shared_ptr 显然是更可取的。
  • @aber 我出于同样的原因对你的投票进行了投票。除非您可能通常不应该使用 shared ptr 如果几乎每次使用都是创建使用。 ;)
【解决方案2】:

答案是肯定的,而且 setB1 一般更好。

  • 复制共享指针会对引用计数进行昂贵(缓慢)的原子递增/递减操作。

  • 移动共享指针几乎是免费的,基本上只是非原子地复制指针(可能是一条汇编指令)。

在您的示例中,setB1 为用户提供了移动或复制 shared_ptr 的选择,从而在用户可以移动时实现最佳性能,而setB2 则强制进行复制。

在此处查看性能差异的详细说明: Why would I std::move an std::shared_ptr?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-06-04
    • 2021-09-24
    • 2014-04-15
    • 2021-12-23
    • 2010-10-04
    • 2021-06-08
    • 2017-07-26
    相关资源
    最近更新 更多