1

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

我已经阅读了C++ FAQ中有关静态初始化惨败的所有内容,并且我想我已经掌握了它——我不明白为什么会发生这种情况,或者为什么会出现这种惨败。

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

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 除了默认构造函数之外都没有任何东西,因此不可能引用其他尚未初始化的静态对象。我理解惨败的方式是,当一个静态对象引用另一个尚未初始化的静态对象时,它就发生了。

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

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

4

2 回答 2

2

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

于 2012-09-28T20:43:22.257 回答
-1

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

建议:

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

恕我直言...

于 2012-09-28T20:11:29.340 回答