移动操作(如移动的构造函数)为std::shared_ptr
是便宜的,因为它们基本上是“偷指针”(从源到目的地;更精确地说,整个状态控制块被从源到目的地“偷”,包括引用计数信息) 。
取而代之的是,对调用原子引用计数的复制操作会增加(即,不仅在整数数据成员上,而且例如在Windows上进行调用)也比仅窃取指针/状态要昂贵。std::shared_ptr
++RefCount
RefCount
InterlockedIncrement
因此,详细分析这种情况下的引用计数动态:
// shared_ptr<CompilerInvocation> sp;
compilerInstance.setInvocation(sp);
如果您sp
按值传递,然后在方法内部进行复制CompilerInstance::setInvocation
,则您将:
- 输入方法时,该
shared_ptr
参数将被复制构造:ref count 原子 增量。
- 在方法的身体,你复制的
shared_ptr
参数为数据成员:引用计数原子 增量。
- 退出方法时,
shared_ptr
参数将被破坏:ref count atomic decrement。
您有两个原子增量和一个原子递减,总共进行了三个 原子操作。
相反,如果您先按shared_ptr
值传递参数,然后std::move
在方法内部传递(如Clang的代码所述),则您将:
- 输入方法时,该
shared_ptr
参数将被复制构造:ref count 原子 增量。
- 在方法的身体,你
std::move
的shared_ptr
参数为数据成员:引用计数并没有改变!您只是在窃取指针/状态:不涉及昂贵的原子引用计数操作。
- 退出方法时,
shared_ptr
参数将被破坏;但是自从您进入第2步以来,没有什么可破坏的,因为该shared_ptr
参数不再指向任何东西。同样,在这种情况下不会发生原子递减。
底线:在这种情况下,您只会获得一个引用计数原子增量,即只有一个原子操作。
如您所见,对于复制案例,这比两个原子增量加一个原子递减(总共三个原子操作)要好得多。