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

发布于 2024-12-19 19:58:58 字数 1529 浏览 2 评论 0原文

给定以下代码:

#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; 才被破坏。为什么?

Given this code:

#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;
}

(You can just paste this directly into a compiler)

The first part of my expected sample output is correct:

Foo()
Foo() 
Bar() 
Foo()
Bar()
Foo(char) 
Foo()
Foo(char)
Bar(char)
~Bar()
~Foo
~Foo()
~Bar()
~Foo()
~Foo()

But I get the destructor output of the two static objects static Bar b1; and static Foo f2('c'); wrong.

The correct answer for the last part is:

~Bar()
~Foo()
~Foo()

I get:

~Foo()
~Bar()
~Foo()

This is my reasoning:

I understand that all local objects are destructed before static objects. Of the two remaining static objects static Bar b1; and static Foo f2('c');, static Foo f2('c'); appears last, so it is destructed first, because destructors are called in the reverse order of their creation.

But static Foo f2('c'); isn't destructed first, static Bar b1; is. Why?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

南风几经秋 2024-12-26 19:58:58

修改你的程序:

#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

编辑:
正如其他人提到的,如果变量来自不同的翻译单元,则具有静态存储持续时间的变量的初始化顺序是不确定的,但当它们位于同一翻译单元中时可以定义它们。

通过构造函数调用进行的初始化(如本示例中所示)称为动态初始化,并且

动态初始化具有静态存储的非局部变量
持续时间可以是有序的,也可以是无序的
。明确的定义
专门的类模板静态数据成员已订购
初始化。其他类模板静态数据成员(即
隐式或显式实例化的专业化)具有无序
初始化。 其他具有静态存储期限的非局部变量
已命令初始化。具有有序初始化的变量
在单个翻译单元中定义的应在
它们在翻译单元中的定义顺序。

是否动态初始化 a 是由实现定义的
具有静态存储持续时间的非局部变量在
main 的第一个语句。如果初始化被推迟到某个时间
main 的第一个语句之后的时间点,它应发生在
中定义的任何函数或变量的第一个 odr-use (3.2)
与要初始化的变量相同的翻译单元。

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

...这样的变量
控件第一次通过其声明时被初始化; ...

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

再次强调,当你有多个翻译时,你最好不要依赖初始化的顺序。

Modified you program :

#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;
}

Which generates the following output in 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

You see that the last destructed one is the non-static global variable Foo f1.

EDIT:
As the others mentioned, the initialization order of variables with static storage duration is unspecific if the variables are from different translation units, but they can be defined when they are in the same translation unit.

Initialization by constructor calls (as in this examples) are called dynamic initialization, and

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.

The initialization of local static variables is specified as

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

And as the destruction of variables with static storage duration should be in the reverse order of their construction, so the order of construction and destruction of the variables with types Foo and Bar in this example is in fact defined.

Again, when you have multiple translation, you'd better not to rely on the order of initialization.

白日梦 2024-12-26 19:58:58

请参阅此 C++ FAQ 条目,静态的初始化顺序对象未定义。 不要依赖它。

See this C++ FAQ entry, the initialization order for static objects is undefined. Don't rely on it.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文