查看以下简单 C++ 函数的汇编输出:
#include <memory>
int square(std::unique_ptr<int> num) {
return *num * *num;
}
Gcc 和 clang 发出以下程序集 ( -O2
):
square(std::unique_ptr<int, std::default_delete<int> >):
mov rax, QWORD PTR [rdi]
mov eax, DWORD PTR [rax]
imul eax, eax
ret
这对我来说非常出乎意料:析构函数在哪里被调用?
另一方面,MSVC 执行了我所期望的操作,并调用析构函数。
这是 Godbolt 重现:https://godbolt.org/z/e66xh9Yos
我还尝试使用更大的类型来int
查看是否是一些小尺寸优化,但情况似乎并非如此。
有人能解释一下这是怎么回事吗?
未指定函数参数对象是在函数返回时销毁还是在包含函数调用的完整表达式末尾销毁。
换句话说,调用者或被调用者是否负责调用析构函数是 ABI 决定的。
Itanium C++ ABI(据我所知除了 MSVC 之外到处都在使用)选择在包含调用的完整表达式的末尾销毁函数参数对象。另一方面,MSVC 的 ABI 选择在函数返回时销毁它们。
该标准明确未指定追溯支持这两个 ABI 决策。
另请注意,调用函数参数对象的构造函数始终是调用者的责任。因此调用者可以像被调用者一样调用析构函数。它从函数声明中知道对象是在哪里构造的以及它的类型是什么。