gpt4 book ai didi

c++ - 使用-fno-ellide-constructors进行编译时连续调用move构造函数

转载 作者:行者123 更新时间:2023-12-01 14:43:16 25 4
gpt4 key购买 nike

在以下代码中(使用-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]

为什么本地Noisy对象 [0x7ffc4445735f]f()中的副本在移入 f的返回地址之后(以及在 b构造开始之前)被破坏了;虽然 g()似乎没有发生同样的事情?
即在后一种情况下(执行 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++ 14中,在[expr.call] / 4中指定的标准是在函数返回时应销毁c。但是,尚不清楚在函数返回哪个阶段的确切含义。提出了CWG问题。

    从C++ 17开始,该规范现在由实现定义,是将y与函数的本地变量同时销毁,还是在包含函数调用的完整表达式的末尾销毁。事实证明,这两种情况无法协调,因为这将是一个重大的ABI更改(请考虑一下,如果y的析构函数抛出异常,会发生什么情况);而且Itanium C++ ABI在完整表达式的末尾指定破坏。

    由于C++ 14措辞含糊,我们不能确定地说y不符合C++ 14,但是由于ABI问题,无论如何现在都不会更改它。

    有关指向标准和CWG报告的链接的说明,请参见以下问题:Sequencing of function parameter destruction以及Late destruction of function parameters

  • 关于c++ - 使用-fno-ellide-constructors进行编译时连续调用move构造函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60717396/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com