移动 std::shared_ptr 的开销?

use*_*312 5 c++ move shared-ptr overhead-minimization

这是一个 C++ 片段。Func1生成一个共享对象,直接移入Func2. 我们认为不应该有开销Func3。将此代码片段放入Compiler Explorer中,我们发现使用 MSVC 的代码比 clang 或 GCC 短 2-3 倍。为什么会这样?可以使用 clang/GCC 获得更短的代码吗?

它看起来像是Func3生成异常处理代码来清理临时共享对象。

#include <memory>

std::shared_ptr<double> Func1();
void Func2 (std::shared_ptr<double> s);

void Func3()
{
  Func2(Func1());
}
Run Code Online (Sandbox Code Playgroud)

Jan*_*tke 6

问题归结为平台 ABI,并且通过完全不透明的类型可以更好地说明:

\n
struct A {\n    A(const A&);\n    A(A&&);\n    ~A();\n};\n\nA make() noexcept;\nvoid take(A) noexcept;\n\nvoid foo() {\n    take(make());\n}\n
Run Code Online (Sandbox Code Playgroud)\n

请参阅编译器资源管理器中的比较

\n

MSVC输出

\n
void foo(void) PROC\n        push    ecx\n        push    ecx\n        push    esp\n        call    A make(void)\n        add     esp, 4\n        call    void take(A)\n        add     esp, 8\n        ret     0\nvoid foo(void) ENDP\n
Run Code Online (Sandbox Code Playgroud)\n

GCC 输出(clang 非常相似)

\n
foo():\n        sub     rsp, 24\n        lea     rdi, [rsp+15]\n        call    make()\n        lea     rdi, [rsp+15]\n        call    take(A)\n        lea     rdi, [rsp+15]\n        call    A::~A() [complete object destructor]\n        add     rsp, 24\n        ret\n
Run Code Online (Sandbox Code Playgroud)\n
\n

如果该类型具有重要的析构函数,则调用者在控制权返回到该析构函数后调用该析构函数(包括调用者抛出异常时)。

\n
\n

- Itanium C++ ABI \xc2\xa73.1.2.3 重要参数

\n

解释

\n

这里发生的事情是:

\n
    \n
  • make()产生类型的纯右值A
  • \n
  • 这被输入到参数中take(A)这被输入到\n
      \n
    • 发生强制复制省略,因此不会调用复制/移动构造函数
    • \n
    \n
  • \n
  • 只有 GCC 和 clang 会破坏A只有 GCC 和 clang在调用站点
  • \n
\n

相反,MSVC 会销毁被调用者内部的临时文件A(或者在您的情况下为std::shared_ptr),而不是在调用站点。您看到的额外代码是内联版本std::shared_ptr析构函数的内联版本。

\n

最后,您应该不会看到任何重大的性能影响。但是,不幸的是,如果Func2重置/释放共享指针,则调用站点的大部分析构函数代码都会失效。此 ABI 问题类似于以下问题std::unique_ptr

\n
\n

还有一个围绕函数参数的销毁顺序和析构函数的执行的语言问题unique_ptr。为了简单起见,本文忽略了这一点,但“通过unique_ptr成本低廉T*”的完整解决方案也必须解决这个问题。

\n
\n\n
\n

也可以看看

\n

阿格纳·雾。-不同C++编译器和操作系统的调用约定

\n

  • Clang 也可以针对 microsoft abi 进行编译,因此这里有一个更直接的比较:https://godbolt.org/z/MWfjPfaMo (3认同)