在以下代码中(使用 -std=c++14 -Wall -fno-elide-constructors
在 gcc 9.2 上构建):
struct Noisy {
Noisy() { std::cout << "Default construct [" << (void*)this << "]\n"; }
Noisy(const Noisy&) { std::cout << "Copy construct [" << (void*)this << "]\n"; }
Noisy(Noisy&&) { std::cout << "Move construct [" << (void*)this << "]\n"; }
Noisy& operator=(const Noisy&) { std::cout << "Copy assignment" << std::endl; return *this; }
Noisy& operator=(Noisy&&) { std::cout << "Move assignment" << std::endl; return *this; }
~Noisy() { std::cout << "Destructor [" << (void*)this << "]\n"; }
};
Noisy f() {
Noisy x;
return x;
}
Noisy g(Noisy y) {
return y;
}
int main(void) {
Noisy a;
std::cout << "--- f() ---\n";
Noisy b = f();
std::cout << "b [" << (void*)&b << "]\n";
std::cout << "--- g(a) ---\n";
Noisy c = g(a);
std::cout << "c [" << (void*)&c << "]\n";
std::cout << "---\n";
return 0;
}
这会产生这样的结果:
Default construct [0x7ffc4445737a]
--- f() ---
Default construct [0x7ffc4445735f]
Move construct [0x7ffc4445737c]
Destructor [0x7ffc4445735f]
Move construct [0x7ffc4445737b]
Destructor [0x7ffc4445737c]
b [0x7ffc4445737b]
--- g(a) ---
Copy construct [0x7ffc4445737e]
Move construct [0x7ffc4445737f]
Move construct [0x7ffc4445737d]
Destructor [0x7ffc4445737f]
Destructor [0x7ffc4445737e]
c [0x7ffc4445737d]
---
Destructor [0x7ffc4445737d]
Destructor [0x7ffc4445737b]
Destructor [0x7ffc4445737a]
为什么 f()
中的本地 Noisy 对象 [0x7ffc4445735f]
的拷贝在移入 f
后立即被破坏的返回地址(在 b
构造开始之前);而 g()
似乎没有发生同样的情况?
IE。在后一种情况下(当 g()
执行时),函数参数 Noisy y
, [0x7ffc4445737e]
的本地拷贝仅在c
已准备好构建。难道它不应该在被移入 g
的返回地址后立即被销毁,就像 f()
发生的情况一样吗?
最佳答案
这些是输出中地址的变量:
0x7ffc4445737a a
0x7ffc4445735f x
0x7ffc4445737c return value of f()
0x7ffc4445737b b
0x7ffc4445737e y
0x7ffc4445737f return value of g()
0x7ffc4445737d c
我将这个问题解释为:您强调以下两点:
x
在构造b
之前被销毁y
在c
构造后被销毁
并询问为什么两种情况的表现不同。
答案是:在 C++14 中,[expr.call]/4 中指定的标准是,当函数返回时,y
应该被销毁。然而,并没有明确指定函数返回的确切含义。提出了 CWG 问题。
从 C++17 开始,规范现在是实现定义的,y
是否与函数的局部变量同时销毁,或者在包含的完整表达式的末尾销毁函数调用。事实证明,这两种情况无法协调,因为这将是一个破坏性的 ABI 更改(想想如果 y 的析构函数抛出异常会发生什么); Itanium C++ ABI 还指定在完整表达式末尾进行销毁。
由于 C++14 措辞的歧义,我们不能明确地说 g++ -std=c++14
不符合 C++14,但无论如何由于 ABI 问题,现在不会更改。
有关标准和 CWG 报告链接的说明,请参阅此问题:Sequencing of function parameter destruction还有Late destruction of function parameters
关于c++ - 使用 -fno-elide-constructors 编译时连续调用 move 构造函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60717396/