Mar*_*rny 10 c++ gcc c++11 visual-studio-2015
在将一些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)));
}
Run Code Online (Sandbox Code Playgroud)
如果我使用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
Run Code Online (Sandbox Code Playgroud)
但是,如果我使用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
Run Code Online (Sandbox Code Playgroud)
GCC调用析构函数f的参数Bar(),之后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;
}
Run Code Online (Sandbox Code Playgroud)
Clang和g ++都产生cXd和MSVC产生cdX.
| 归档时间: |
|
| 查看次数: |
212 次 |
| 最近记录: |