鉴于此代码:
#include <iostream>
using namespace std;
class Foo {
public:
Foo () { c = 'a'; cout << "Foo()" << endl; }
Foo (char ch) { c = ch; cout << "Foo(char)" << endl; }
~Foo () { cout << "~Foo()" << endl; }
private:
char c;
};
class Bar : public Foo {
public:
Bar () { cout << "Bar()" << endl; }
Bar (char ch) : Foo(ch) { cout << "Bar(char)" << endl; }
~Bar () { cout << "~Bar()" << endl; }
};
Foo f1; static Bar b1;
int main()
{
Bar b2;
{
static Foo f2('c');
Foo f3;
Bar b3 ('d');
}
return 0;
}
(您可以直接将其粘贴到编译器中)
我预期的样本输出的第一个部分是正确的:
Foo()
Foo()
Bar()
Foo()
Bar()
Foo(char)
Foo()
Foo(char)
Bar(char)
~Bar()
~Foo
~Foo()
~Bar()
~Foo()
~Foo()
但是我得到了两个静态对象static Bar b1;
和static Foo f2('c');
的析构函数输出错误。
最后一部分的正确答案是:
~Bar()
~Foo()
~Foo()
我明白了:
~Foo()
~Bar()
~Foo()
这是我的理由:
我知道在静态对象之前所有本地对象都被破坏了。在剩余的两个静态对象static Bar b1;
和static Foo f2('c');
中,static Foo f2('c');
出现 last ,因此它首先被破坏,因为析构函数被调用按照他们创造的相反顺序。
但static Foo f2('c');
首先没有被破坏,static Bar b1;
是。为什么呢?
答案 0 :(得分:3)
修改了你的程序:
#include <iostream>
using namespace std;
class Foo {
public:
Foo () { c = 'a'; cout << "Foo()" << endl; }
Foo (char ch) { c = ch; cout << "Foo(char)" << ch << endl; }
~Foo () { cout << "~Foo()"<< c << endl; }
protected:
char c;
};
class Bar : public Foo {
public:
Bar () { cout << "Bar()" << endl; }
Bar (char ch) : Foo(ch) { cout << "Bar(char)" << ch << endl; }
~Bar () { cout << "~Bar()" << c << endl; }
};
Foo f1('a'); static Bar b1('b');
int main()
{
Bar b2('c');
{
static Foo f2('d');
Foo f3('e');
Bar b3 ('f');
}
return 0;
}
在g ++ 4.5.2中生成以下输出:
Foo(char)a
Foo(char)b
Bar(char)b
Foo(char)c
Bar(char)c
Foo(char)d
Foo(char)e
Foo(char)f
Bar(char)f
~Bar()f
~Foo()f
~Foo()e
~Bar()c
~Foo()c
~Foo()d
~Bar()b
~Foo()b
~Foo()a
您会看到最后一个被破坏的是非静态全局变量Foo f1
。
编辑: 正如其他人所提到的,如果变量来自不同的翻译单元,那么具有静态存储持续时间的变量的初始化顺序是非特定的,但是当它们在同一个翻译单元中时可以定义它们。
构造函数调用的初始化(如本例所示)称为dynamic initialization
和
使用静态存储动态初始化非局部变量 持续时间是有序的还是无序的。明确的定义 专门的类模板静态数据成员已订购 初始化。其他类模板静态数据成员(即 隐式或显式实例化的特化)具有无序性 初始化。 具有静态存储持续时间的其他非局部变量 已订购初始化。有序初始化的变量 在单个翻译单元中定义的内容应在 它们在翻译单元中的定义顺序。
它是实现定义的动态初始化 具有静态存储持续时间的非局部变量在之前完成 主要的第一个声明。如果初始化推迟到某些 在主要的第一个陈述之后的时间点,它应该在之前发生 第一个odr-use(3.2)中定义的任何函数或变量 与要初始化的变量相同的翻译单元。
本地静态变量的初始化指定为
......这样的变量 在控制第一次通过其声明时初始化; ...
由于具有静态存储持续时间的变量的销毁应与其构造的顺序相反,因此在此示例中类型为Foo
和Bar
的变量的构造和销毁顺序为事实上已定义。
同样,当你有多个翻译时,你最好不要依赖初始化的顺序。
答案 1 :(得分:-1)
请参阅this C++ FAQ entry,未定义静态对象的初始化顺序。 不要依赖它。