gpt4 book ai didi

c++ - 函数参数的析构函数在 gcc 和 MSVC 中被不同地调用

转载 作者:可可西里 更新时间:2023-11-01 16:06:31 25 4
gpt4 key购买 nike

在将一些 C++ 代码从 Microsoft Visual Studio 移植到 gcc 时,我遇到了一个奇怪的错误,我最终将其归结为:

#include <iostream>
using namespace std;

class Foo {
public:
int data;
Foo(int i) : data(i)
{
cout << "Foo constructed with " << i << endl;
}
Foo(const Foo& f) : data(f.data)
{
cout << "copy ctor " << endl;
}
Foo(const Foo&& f) : data(f.data)
{
cout << "move ctor" << endl;
}
~Foo()
{
cout << "Foo destructed with " << data << endl;
}
};

int Bar(Foo f)
{
cout << "f.data = " << f.data << endl;
return f.data * 2;
}

int main()
{
Foo f1(10);
Foo f2(Bar(std::move(f1)));
}

如果我使用 Microsoft Visual Studio 2015 Community 编译并运行上述代码,我会得到以下输出:

Foo constructed with 10
move ctor
f.data = 10
Foo destructed with 10
Foo constructed with 20
Foo destructed with 20
Foo destructed with 10

但是,如果我使用 gcc 6.1.1 和 --std=c++14 编译并运行代码,我会得到以下输出:

Foo constructed with 10
move ctor
f.data = 10
Foo constructed with 20
Foo destructed with 10
Foo destructed with 20
Foo destructed with 10

gcc 在 Bar() 返回后调用 f 的析构函数,Bar() 的参数,而 msvc 调用析构函数 (显然)在它返回之前,或者至少在 f2 的构造函数之前。根据 C++ 标准,什么时候 f 应该被析构?

最佳答案

他们都很好;这取决于。标准中似乎没有明确规定。

来自 [expr.call]/4 (这个措辞可以追溯到 C++98);

The lifetime of a parameter ends when the function in which it is defined returns. The initialization and destruction of each parameter occurs within the context of the calling function.

还有 CWG#1880 ;

WG decided to make it unspecified whether parameter objects are destroyed immediately following the call or at the end of the full-expression to which the call belongs.

g++(和 clang)和 MSVC 的行为都是正确的,实现可以自由选择一种方法。

总而言之,如果您拥有的代码依赖于此排序,我会更改它以使排序更具确定性 - 如您所见,它会导致细微的错误。


此行为的一个简化示例是;

#include <iostream>
struct Arg {
Arg() {std::cout << 'c';}
~Arg() {std::cout << 'd';}
Arg(Arg const&) {std::cout << 'a';}
Arg(Arg&&) {std::cout << 'b';}
Arg& operator=(Arg const&) {std::cout << 'e'; return *this;}
Arg& operator=(Arg&&) {std::cout << 'f'; return *this;}
};
void func(Arg) {}
int main() {
(func(Arg{}), std::cout << 'X');
std::cout << std::endl;
}

Clang 和 g++ 都产生 cXd 而 MSVC 产生 cdX

关于c++ - 函数参数的析构函数在 gcc 和 MSVC 中被不同地调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37155404/

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