微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

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

在将一些C代码从Microsoft Visual Studio移植到 gcc时,我遇到了一个奇怪的bug,我最终归结为:
#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 举报,一经查实,本站将立刻删除。

相关推荐