#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
gcc调用f的析构函数,Bar()的参数在Bar()返回后,而msvc在返回之前调用析构函数(显然),或至少在构造函数f2之前.根据C标准,什么时候f被破坏?
解决方法
从[expr.call]/4(这个措辞可以追溯到C98);
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.
原文地址:https://www.jb51.cc/c/113129.html
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。