【问题标题】:Does the C++ static initialization fiasco apply to class hierarchy?C++ 静态初始化惨败是否适用于类层次结构?
【发布时间】:2012-09-28 20:05:28
【问题描述】:

我在静态初始化中遇到了崩溃(调试断言失败:VC++ 2008 中的 CRT 堆指针无效),我不确定我是否理解原因。

我已经在 C++ FAQ 上阅读了有关 static initialization fiasco 的所有内容,我想我已经掌握了它——我不明白为什么会发生这种情况,或者为什么会出现这种情况惨败。

这就是这种情况(为了简洁起见,大多数非静态成员都被省略了)。我有一个类,A,在 A.h 中定义:

class A {
public:
    virtual ~A() { }

    virtual void do_something();
};

然后,我有一个类 C,它有一个嵌套类 B,它是 A 的子类。C 还包含 B 类型的私有静态成员:

class C {
public:
    void do_the_C_thing();

private:
    class B : public A {
    public:
        virtual void do_something();
    };

    static B my_personal_B;
};

最后是C的实现文件,C.cpp,里面包含了my_personal_B的存储单元:

C::B my_personal_B;

C::C() {
}

C::do_the_C_thing() {
    // [...]
    my_personal_B.do_something();
    // [...]
}

void C::B::do_something() {
    // overridden do_something for C's private B class
}

这种模式在很多类中重复出现,每个类都有一个继承自 A 的嵌套类。通过几次代码修订,这一切都可以完美运行,但最近应用程序崩溃并出现以下特定错误消息:

调试断言失败!

程序:
[已编辑].exe
文件:f:\dd\vctools\crt_bld\self_x86\crt\src\dbgheap.c
线路:1511

表达式:_CrtIsValidHeapPointer(pUserData)

如果我点击调试,我会看到 C.cpp 中定义静态成员的行。

这看起来不像是静态的惨败,因为没有任何静态引用 my_personal_B,A 和 B 除了默认构造函数之外都没有任何东西,因此不可能引用其他尚未初始化的静态对象。我理解惨败的方式是,当一个静态对象引用另一个尚未初始化的静态对象时,它就发生了。

不过,如果我将静态成员更改为首次使用时初始化的方法,崩溃似乎就消失了。

所以问题是,为什么会崩溃?

【问题讨论】:

  • 1.什么时候崩溃? 2.什么是调用栈?

标签: visual-studio-2008 visual-c++ static-initialization


【解决方案1】:

A 类具有虚函数。这意味着编译器会生成一个名为 vtable 的静态对象来保存指向成员函数的指针。因此,尽管您没有在 A 类中定义任何静态对象,但编译器必须这样做。 B 类依赖于该 vtable(对于 A 的虚拟析构函数,如果没有别的)。显然,初始化代码现在正在尝试在 A 的 vtable 构造之前创建 B 类型的对象。

【讨论】:

  • Ohhhhh,好吧,这是有道理的,并解释了为什么直到最近我将虚拟析构函数声明添加到 A 时才出现(以前,A 层次结构中没有类有析构函数,但这已经改变了)。 (因为我是一个低代表的新海报,我不能赞成你的回应......对不起)
【解决方案2】:

伙计,你为什么要依赖静态初始化?你能说“设计错误”吗?

建议:

如果你不能改变设计,至少一定要设置一个标志“bInitialized”,这样依赖的客户端就可以检查你的对象是否真的被初始化了,并优雅地失败。

恕我直言...

【讨论】:

  • 这是评论,不是答案。
猜你喜欢
  • 1970-01-01
  • 2011-07-15
  • 1970-01-01
  • 2015-07-01
  • 1970-01-01
相关资源
最近更新 更多