C++:在对象范围外调用析构函数?

Jus*_*tin 5 c++ destructor

更新1:按建议添加打印"this".

更新2:拆分为多个文件以尝试阻止gcc优化.

更新3:记录的复制构造函数并输入添加功能.

更新4:添加了Clang的输出和main中的第二个cout.

我希望将参数析构函数作为函数中的最后一个语句来调用.从此以后,我希望下面的代码输出如下.

default constructor: 008DFCF8
other constructor: 008DFCEC
copy constructor: 008DFBC0
in member add
destroying: 008DFBC0
copy constructor: 008DFBB8
copy constructor: 008DFBB4
in function add
destroying: 008DFBB4
destroying: 008DFBB8
3 == 3
end of main
destroying: 008DFCEC
destroying: 008DFCF8
Run Code Online (Sandbox Code Playgroud)

使用MSVC(Visual Studio)时,输出是预期的.但GCC(4.8.2-19ubuntu1)输出以下内容,表明函数参数的析构函数是在main()中的第一个cout语句之后但在最后一个之前调用的.

default constructor: 0x7fff2fcea510
other constructor: 0x7fff2fcea520
copy constructor: 0x7fff2fcea550
in member add
copy constructor: 0x7fff2fcea540
copy constructor: 0x7fff2fcea530
in function add
3 == 3
destroying: 0x7fff2fcea530
destroying: 0x7fff2fcea540
destroying: 0x7fff2fcea550
end of main
destroying: 0x7fff2fcea520
destroying: 0x7fff2fcea510
Run Code Online (Sandbox Code Playgroud)

对于那些好奇的clang ++(3.4-1ubuntu3)输出.

default constructor: 0x7fff52cf9878
other constructor: 0x7fff52cf9870
copy constructor: 0x7fff52cf9860
copy constructor: 0x7fff52cf9858
in function add
3 == copy constructor: 0x7fff52cf9850
in member add
3
destroying: 0x7fff52cf9850
destroying: 0x7fff52cf9858
destroying: 0x7fff52cf9860
end of main
destroying: 0x7fff52cf9870
destroying: 0x7fff52cf9878
Run Code Online (Sandbox Code Playgroud)

问题:

  1. 我最初的怀疑是海湾合作委员会正在强调这些职能?如果这是真的,有没有办法禁用此优化?
  2. C++规范中的哪个部分允许在main中的cout之后调用析构函数?特别感兴趣的是内联规则,如果相关,以及何时安排析构函数.

// Test.h
#ifndef __TEST_H__

#include <iostream>

using namespace std;

class Test
{
public:
    int val;

    Test(Test const &a) : val(a.val)
    {
        cout << "copy constructor: " << this << endl;
    }

    Test() : val(1)
    {
        cout << "default constructor: " << this << endl;
    }

    Test(int val) : val(val)
    {
        cout << "other constructor: " << this << endl;
    }

    ~Test()
    {
        cout << "destroying: " << this << endl;
    }

    int add(Test b);
};

#endif
Run Code Online (Sandbox Code Playgroud)
// Add.cpp
#include "Test.h"

int Test::add(Test b)
{
    cout << "in member add" << endl;
    return val + b.val;
}

int add(Test a, Test b)
{
    cout << "in function add" << endl;
    return a.val + b.val;
}
Run Code Online (Sandbox Code Playgroud)
// Main.cpp
#include "Test.h"

int add(Test a, Test b);

int main()
{
    Test one, two(2);

    cout << add(one, two) << " == " << one.add(two) << endl;

    cout << "end of main" << endl;

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

使用以下方法编制GCC:

g++ -c Add.cpp -o Add.o ; g++ -c Main.cpp -o Main.o ; g++ Add.o Main.o -o test
Run Code Online (Sandbox Code Playgroud)

Mic*_*urr 2

似乎 C++ 标准对于何时必须调用函数参数析构函数可能有点含糊。C++03和C++11都在5.2.2/4“函数调用”中说(添加了强调):

当定义参数的函数返回时,参数的生命周期结束。每个参数的初始化和销毁​​都发生在调用函数的上下文中。

因此,参数的析构函数在概念上不会出现在函数的右大括号处。这是我不知道的事情。

该标准给出了一个注释,解释了这意味着如果参数的析构函数抛出,则仅考虑调用函数或“更高层”的异常处理程序(具体来说,即使被调用函数具有“函数尝试块”,不予考虑)。

虽然我认为其目的是为了 MSVC 行为,但我可以看到有人会如何解释允许 GCC 行为的读数。

话又说回来,也许这是 GCC 中的一个错误?