为什么我会std ::移动一个std :: shared_ptr?

我一直在查看Clang的源代码 ,发现这个代码片段:

void CompilerInstance::setInvocation( std::shared_ptr<CompilerInvocation> Value) { Invocation = std::move(Value); } 

为什么我要std::move一个std::shared_ptr

在共享资源上转让所有权有没有意义?

为什么我不这样做呢?

 void CompilerInstance::setInvocation( std::shared_ptr<CompilerInvocation> Value) { Invocation = Value; } 

我认为其他答案没有强调的是速度

std::shared_ptr引用计数是primefaces的 。 增加或减less参考计数需要primefaces增量或减量 。 这比非primefaces增量/减量要慢百倍,更不用说如果我们增加和减less同一个计数器,我们就得到确切的数字,浪费了大量的时间和资源。

通过移动shared_ptr而不是复制它,我们“窃取”primefaces引用计数,并且使其他shared_ptr无效。 “偷取”引用计数不是primefaces的,比复制shared_ptr (和caterprimefaces引用的增量或减量)要快上百倍。

请注意,这种技术纯粹用于优化。 复制它(正如你所build议的)同样也是function强大的。

通过使用move您避免增加,然后立即减less股份数量。 这可以为您节省一些昂贵的primefaces操作的使用计数。

std::shared_ptr 移动操作(如移动构造函数)很便宜 ,因为它们基本上是“窃取指针” (从源到目标;更准确地说,整个状态控制块从源到目标“被盗”,包括引用计数信息)。

而是在std::shared_ptr复制操作,调用primefaces引用计数增加(即,不仅仅是在整数RefCount数据成员上的++RefCount ,而是例如在Windows上调用InterlockedIncrement ),这比仅仅窃取指针/状态更昂贵

因此,详细分析这种情况下的参考计数dynamic:

 // shared_ptr<CompilerInvocation> sp; compilerInstance.setInvocation(sp); 

如果你通过值传递sp ,然后在CompilerInstance::setInvocation方法中获取一个副本 ,你有:

  1. 当进入方法时, shared_ptr参数被复制构造:ref count atomic increment
  2. 在方法体内部, shared_ptr参数复制到数据成员中:ref count atomic increment
  3. 退出该方法时, shared_ptr参数被破坏:ref count atomic decrement

你有两个primefaces增量和一个primefaces减量,总共三个 primefaces操作。

相反,如果你通过value来传递shared_ptr参数,然后std::move在方法内(正如Clang的代码所做的那样),你有:

  1. 当进入方法时, shared_ptr参数被复制构造:ref count atomic increment
  2. 在方法体内部, std::move shared_ptr参数std::move到数据成员中:ref count不会改变! 你只是在窃取指针/状态:不涉及昂贵的primefaces引用计数操作。
  3. 退出该方法时, shared_ptr参数被破坏; 但是因为你在步骤2中移动了,所以没有什么可以破坏的,因为shared_ptr参数没有指向任何东西。 同样,在这种情况下不会发生primefaces减量。

底线:在这种情况下,只有一个引用计数primefaces增量,即只有一个primefaces操作。
正如你所看到的,这比两个primefaces增量加上一个primefaces减量(总共三个primefaces操作)要好得多

复制shared_ptr包括复制其内部状态对象指针并更改引用计数。 移动它只涉及交换指针到内部引用计数器和拥有的对象,所以它更快。

在这种情况下使用std :: move有两个原因。 大部分的回应都是针对速度问题,而忽略了更清楚地显示代码意图的重要问题。

对于std :: shared_ptr,std :: move明确表示指针对象所有权的转移,而简单的复制操作则添加了其他所有者。 当然,如果原来的所有者随后放弃其所有权(例如通过允许它们的std :: shared_ptr被销毁),则所有权的转移已经完成。

当你用std :: move转移所有权时,很明显发生了什么事情。 如果您使用普通副本,则直到您确认原始所有者立即放弃所有权后,才能确定所执行的操作并不明显。 作为奖励,更有效的实现是可能的,因为所有权的primefaces转移可以避免业​​主数量增加了一个临时状态(以及随之而来的参考数量的变化)。