2011-12-06 27 views
3

鉴于此代码:(简单的C++概念)构造的意外输出/析构函数调用

#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');出现最后,所以它被破坏第一个,因为析构函数按照它们创建的相反顺序被调用。

但是static Foo f2('c');不是先破坏,static Bar b1;是。为什么?

+0

您应该添加一个成员变量来区分不同的对象。 – fefe

+0

仅供参考:当使用g ++时,我得到了你期望得到的结果4.6.1 –

+0

C++与Eclipse(MinGW)和Microsoft Visual Studio(禁用语言扩展)仍然输出“正确”的答案,而不是我的预期输出。 – Jason

回答

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,和一个非局部变量的具有静态存储 持续时间

动态初始化或者有序或无序。明确定义 专用类模板静态数据成员已经订购了 初始化。其他类模板静态数据成员(即 隐式或显式实例化的特化)具有无序的 初始化。具有静态存储持续时间的其他非局部变量 已经有序初始化。在单个翻译单元中定义的有序初始化 的变量应在翻译单元中以其定义的 顺序进行初始化。

它是执行定义是否在 主要的第一条语句之前完成具有静态存储持续时间的非本地变量的动态初始化。如果初始化在main的第一个语句后的某个时间点推迟到某个 时间点,则它应该在 之前发生在与要初始化的变量相同的翻译单元中定义的任何函数或变量的第一个odr-use(3.2)。

局部静态变量的初始化被指定为

...这样的可变 初始化首次控制穿过它的声明; ...

,并作为具有静态存储时间变量的破坏应该是在其结构相反的顺序,所以用类型FooBar在这个例子中,变量的构造和析构的顺序其实定义。

同样,当你有多个翻译时,你最好不要依赖初始化的顺序。

+0

+1不错。 。 。 。 –

+0

我看到......'a'是一个全局对象,而不是本地对象。全局和静态对象按其创建顺序被破坏。他们的创作顺序是> b> b> d,所以他们的破坏顺序必须是d> b> b> a。我的错误是将'a'视为本地对象。这是一个全局对象,因为它是在main()之外声明的。 – Jason

-1

请参阅this C++ FAQ entry,静态对象的初始化顺序是未定义的。 不要依靠它。

+1

-1“静态对象的初始化顺序未定义”不正确,它不是FAQ说的内容。不同翻译单元之间的初始化顺序未指定。翻译单位内的订单一般都有明确的定义。 C++ 11§3.6.2/ 2“显式专用类模板静态数据成员的定义已经有序初始化,其他类模板静态数据成员(即隐含或显式实例化的特化)具有无序初始化。存储时间有序初始化。“ –

+0

你说得对。 :-) – Andre