c++ - (简单 C++ 概念)构造函数/析构函数调用的意外输出

标签 c++ inheritance constructor destructor

给定这段代码:

#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; 是。为什么?

最佳答案

修改了你的程序:

#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 , 和

Dynamic initialization of a non-local variable with static storage duration is either ordered or unordered. Definitions of explicitly specialized class template static data members have ordered initialization. Other class template static data members (i.e., implicitly or explicitly instantiated specializations) have unordered initialization. Other non-local variables with static storage duration have ordered initialization. Variables with ordered initialization defined within a single translation unit shall be initialized in the order of their definitions in the translation unit.

It is implementation-defined whether the dynamic initialization of a non-local variable with static storage duration is done before the first statement of main. If the initialization is deferred to some point in time after the first statement of main, it shall occur before the first odr-use (3.2) of any function or variable defined in the same translation unit as the variable to be initialized.

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

... such a variable is initialized the first time control passes through its declaration; ...

并且由于具有静态存储持续时间的变量的销毁应该按照其构造的相反顺序,因此类型为Foo的变量的构造和销毁顺序和 Bar在这个例子中实际上是定义的。

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

关于c++ - (简单 C++ 概念)构造函数/析构函数调用的意外输出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8395848/

相关文章:

c++ - 未收到 ZMQ 消息

c++ - 二叉树搜索和跟踪

具有可变数字或参数的函数的 C++ 静态编译

javascript - 在 JavaScript 中,如何将未实例化的对象传递给不同类的构造函数调用,该类稍后在时间轴中实例化?

java - 依赖项更改时强制类重新编译

c# - 用派生类覆盖基类的属性

java - 我的 Java 中的 ShapeApp 出现问题

javascript - 数组中的对象位于构造函数中

C#如何继承默认构造函数

c# - 如何在 C# 中调用 protected 构造函数?