[英]Destructor of a function argument being called differently in gcc and MSVC
在将一些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社区编译并运行上面的代码,我会得到以下输出:
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
在Bar()
返回之后,gcc调用f
的析构f
, Bar()
的参数,而msvc在返回之前调用析构函数(显然),或者至少在f2
的构造函数之前调用析构函数。 当f
应该被破坏,根据C ++标准?
他们没事; 这取决于。 标准似乎没有具体说明。
来自[expr.call] / 4 (这个措辞可以追溯到C ++ 98);
参数的生命周期在定义它的函数返回时结束。 每个参数的初始化和销毁发生在调用函数的上下文中。
而CWG#1880 ;
WG决定不确定参数对象是在调用之后立即销毁还是在调用所属的完整表达式结束时销毁。
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
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.