【问题标题】:static object and member method called before constructor在构造函数之前调用的静态对象和成员方法
【发布时间】:2012-10-04 10:03:16
【问题描述】:

我有两个类 A 和 B,因此 A 有一个静态 B 实例作为其成员。 B 有一个函数 Show(),这是我的 A 类:

class A
{
  A()
  {
    _b.Show();
  }
private:

  static B _b; 
};

后面的代码是

A a;
B A::_b;

int main()
{
}

现在 B::Show() 在构造 B 之前调用,因为我已经定义了序列 一个和_b。但这究竟是如何工作的,即如何调用仍未构造的对象?

【问题讨论】:

  • 你能发布一个编译的例子吗?我想亲眼看看。

标签: c++ static constructor


【解决方案1】:

这是不可能的,这是未定义的行为(在这种情况下,因为您正在访问一个未初始化的对象),因为 aA::_b 之前初始化。

查找静态初始化顺序惨败。您不会收到错误,因为 99% 的情况都会发生这种情况,而且不容易诊断。

【讨论】:

  • hmmm.. 但它是如何工作的呢?虽然是错误的,但是这样的电话怎么可能呢?你能解释一下它为什么起作用的底层细节吗?
  • @Arun 从技术上讲,UB 意味着任何事情都有可能发生。在实践中,如果_b.Show(); 不访问_b 的内存(调用是静态解决的)它不会崩溃。即使它崩溃了也可能不会崩溃,因为内存在那里,尽管未初始化。
  • 嗯,不,不是所谓的“静态初始化命令惨败”;这指的是在不同翻译单元中定义的静态对象的未指定初始化顺序。这段代码中的初始化顺序定义的很好,问题就是定义写错了。
【解决方案2】:

这是静态初始化顺序问题。在一般情况下很难解决,但解决某些情况的一种方法是将依赖项放在这样的函数中:

class A
{
public:
    A()
    {
        getB().Show();
    }
private:
    static B& getB()
    {
        static B b;
        return b;
    }
};

函数内的静态保证在第一次调用它时被初始化。此外,在 C++11 中,这也保证是线程安全的。

进一步阅读:

http://www.parashift.com/c++-faq/static-init-order-on-first-use.html

Finding C++ static initialization order problems

【讨论】:

    【解决方案3】:

    怎么可能调用一个仍然不存在的对象? 建好了吗?

    嗯,简单的答案就是,代码就是这样做的。 <g>。在同一翻译单元的文件范围内定义的对象是按照其定义发生的顺序构造的,因此如果一个对象的构造函数依赖于另一个对象,则必须确保在构造函数时已经构造了第二个对象第一个对象运行。

    C++ 在这里没有提供任何帮助。你必须自己跟踪它。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-09-28
      • 1970-01-01
      • 1970-01-01
      • 2014-12-07
      • 1970-01-01
      • 2021-04-28
      • 2014-02-25
      • 2014-07-19
      相关资源
      最近更新 更多