【发布时间】:2014-10-08 05:09:42
【问题描述】:
更新 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
使用 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
对于那些对 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
问题:
- 我最初的怀疑是 GCC 是内联函数?如果这是真的,是否有办法禁用此优化?
- 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
// 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;
}
// 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;
}
为 GCC 编译使用:
g++ -c Add.cpp -o Add.o ; g++ -c Main.cpp -o Main.o ; g++ Add.o Main.o -o test
【问题讨论】:
-
GCC 通过在编译期间用
3替换它们来优化对add的调用。尝试在单独的单元中编译add并将两者链接起来。 -
现在,您知道为什么在输出中只看到两个构造函数和 5 个析构函数吗?你能分辨出哪些对象对应于输出中的每一行吗?
-
我将代码拆分为几个文件,但使用 GCC 仍然得到相同的结果。我也不明白为什么有 2 个构造函数但有 5 个析构函数。至少 GCC 和 MVSC 在这点上是一致的。
-
也许你可以澄清“表明析构函数在对象超出范围后被调用”。是什么让你这么想?您认为哪些对象超出了范围,在哪里?
-
析构函数的日志比构造函数多,因为编译器生成的复制构造函数没有日志记录。
标签: c++ destructor