【问题标题】:This static class field is being used before it's been created?这个静态类字段在创建之前就被使用了?
【发布时间】:2017-06-28 04:03:19
【问题描述】:

所以,我一直在尝试使用静态类字段(尤其是常量字段),然后自己进入了......这个:

#include <iostream>
#include <conio.h>

class Test {
public:
    Test() { std::cout << "Constructing (Default CTOR)\n"; }
    Test(int f) { std::cout << "Constructing (Int arg CTOR)\n"; }

    void method() const { std::cout << "Already constructed and being used\n"; }
};

class Stack {
public:
    // static const Test what{ 5 }; // - "element of type "const Test" can not have an initializer inside of a class"
    // const Test ok{ 5 }; // now it can (?)

    static const Test what;

    Stack() {
        what.method();
    }

    // Stack() : what{5} {} // can't do that because "what" will be dependent on object creation (which is not how static class fields roll)
};

Stack obj;

const Test Stack::what{};

int main()
{
    _getch();
    return 0;
}

输出:

显然,Stack 中的 static const Test what 是在实际创建之前使用的(?)。

之后我又进行了一次测试:

#include <iostream>
#include <conio.h>

class Test {
public:
    int data;

    Test() { std::cout << "CONSTRUCTING (Default CTOR)\n"; } // notice, value-initialization of 'data' has been removed
    Test(int f) : data{ f } { std::cout << "CONSTRUCTING (Int arg CTOR)\n"; }

    void method() const { std::cout << "ALREADY CONSTRUCTED AND BEING USED :)\n" << data << std::endl; }
};

class Stack {
public:
    static const Test what;

    Stack() {
        what.method();
    }
};

Stack obj;

const Test Stack::what{ 5 };

int main()
{
    obj.what.method();

    _getch();
    return 0;
}

在这段代码中,我希望看到某种错误,但输出最终看起来像这样:

我对这里发生的事情有一些假设,但我不确定它们是否正确。所以,如果他们是,请纠正我。

这是我的假设:

基本上,静态变量是在程序的一开始创建的(并且是值初始化的),并在程序的最后(当你真正关闭你的 .exe 时)被销毁。 在我的示例中,Stack 类中有一个静态常量变量what,我认为它是在我的程序值初始化开始时创建的。这就是为什么它的data 字段设置为0,我们可以使用它的方法。但我不认为这是正确的,因为它会将Constructing (Default CTOR) 输出到控制台中。所以我有点卡在那里......

我也无法理解为什么我的第一个示例中的注释行是非法的。它们究竟违反了哪些静态/常量类字段规则?

如果您对我的示例中发生的事情有任何想法,请解释一下。

感谢您的关注。

【问题讨论】:

  • 我怀疑这与默认构造函数实际上并未修改对象中的任何内容有关。如果将第二个默认构造函数更改为 : data {1} 会发生什么?
  • @Barmar,什么都没有。输出还是一样,没有错误。
  • 因为你#include &lt;conio.h&gt;我无法编译你的代码。如果您坚持使用标准 C++,我可能会为您提供帮助。
  • @nwp 只有一行依赖于 conio.h,_getch(();。当然,您可以弄清楚如何用标准 C++ 替换它。
  • 我相信这是预期的行为。静态对象的构造函数按照它们在编译单元中出现的顺序被调用;不同编译单元中静态对象的构造顺序未定义。您可以从从静态构造函数调用的代码中引用未构造的静态对象。与某些语言不同,在引用类中的静态对象之前没有调用“类构造函数”。现在我邀请真正阅读规范的人指出我错在哪里......

标签: c++ static-variables class-constants


【解决方案1】:

命名空间范围内的静态变量(即不在函数内部)按照它们在源文件中的定义顺序构造。此排序仅适用于同一源文件中的变量之间,而不适用于不同源文件之间。

所以obj 总是在what 之前构造。对于具有构造函数但在调用构造函数之前的对象,可以做的事情是有限的;并且调用成员函数不是其中之一(C++ 14 [basic.life]/5.2)。所以 Stack 的构造函数中的调用 what.method() 会导致未定义的行为。

【讨论】:

  • 啊,我明白了。感谢您提供信息丰富的答案!所以我的第二个例子输出中的零毕竟应该是一个错误:)
猜你喜欢
  • 2017-03-28
  • 2011-03-26
  • 2016-09-08
  • 1970-01-01
  • 2020-12-29
  • 1970-01-01
  • 2014-02-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多