C++ 为什么无法消除这种独特的存储?

C++ 为什么无法消除这种独特的存储?,c++,gcc,compiler-optimization,abi,C++,Gcc,Compiler Optimization,Abi,为什么编译器会生成: void f(unique_ptr<int> u); void h(int x) { auto p = make_unique<int>(x); f(move(p)); } 在h()的末尾,假设在调用f?之后,p始终是nullptr,在这两种情况下,答案都是:因为从中移动的对象仍将被销毁 如果您查看为调用生成的代码 call operator delete(void*, unsigned long) 与名称可能暗示的相反,

为什么编译器会生成:

void f(unique_ptr<int> u);

void h(int x) {
    auto p = make_unique<int>(x);
    f(move(p));
}

h()
的末尾,假设在调用
f

之后,p始终是
nullptr
,在这两种情况下,答案都是:因为从中移动的对象仍将被销毁

如果您查看为调用生成的代码

call    operator delete(void*, unsigned long)

与名称可能暗示的相反,
std::move()
实际上并不移动对象。它所做的一切都被转换为一个右值引用,该引用允许该引用的接收者从所引用的对象移动,如果他这样选择的话。实际移动只会发生,例如,当通过移动构造函数从给定参数构造另一个对象时。由于编译器不知道在定义
h()
f()
内部发生了什么,因此它不能假定
f()
总是从给定对象移动。例如,
f()。因此,编译器必须假设函数可能返回而不离开对象,并且必须为析构函数发出
delete
。该函数还可以执行移动分配,而不是移动构造,在这种情况下,仍然需要外部析构函数来释放以前由新对象的分配所有权所持有的对象的所有权…

初步猜测:安腾ABI要求调用方处理参数的构造/销毁。运算符delete实际上是为复制的参数
u
调用的。因此,被叫方需要将unique_ptr设置为nullptr以请求被叫方销毁。谢谢。我只是在安腾ABI规范中发现了这一点。当它跨越ABI边界时,
unique\u ptr
似乎不是零成本。至少,由于调用约定,我们需要另一层间接寻址,这样的情况禁止对未使用的DTR进行优化。问题是:与什么替代方案相比,成本不是零?传递
唯一\u ptr
在语义上与传递原始指针不同。如果您想要单一所有权语义,那么您必须以某种方式向调用者发回信号,告知是否存在所有权转移,即使您只是传递一个原始指针而不是一个
unique\u ptr
…与使用OwnerPtr=T*
相比,让
f
的参数为
OwnerPtr
并让
f
确定是否调用删除器(实际上,这是所有权的实现),安腾ABI强制通过引用传递
unique_ptr
,并由调用方销毁,这禁止了dtor的优化(因为只有
f
知道是否应该销毁,但调用方不知道)。
void f(unique_ptr<int> u);

void h(int x) {
    auto p = make_unique<int>(x);
    f(move(p));
}
call    operator delete(void*, unsigned long)
void f(unique_ptr<int> u);
void h(int x) {
    auto p = make_unique<int>(x);
    f(move(p));
}