Does the C++ static initialization fiasco apply to class hierarchy?
-
04-07-2021 - |
문제
I'm getting a crash (debug assertion failure: invalid CRT heap pointer in VC++ 2008) in static initialization, and I'm not sure I understand why.
I've read all about the static initialization fiasco over at the C++ FAQ, and I thought I had a grasp on it--I don't understand why this is happening, or why it would be a case of the fiasco.
So here's the situation (most non-static members are omitted for the sake of brevity). I have one class, A, defined in A.h:
class A {
public:
virtual ~A() { }
virtual void do_something();
};
Then, I have a class, C, which has a nested class, B, which is a subclass of A. C also contains a private static member of type B:
class C {
public:
void do_the_C_thing();
private:
class B : public A {
public:
virtual void do_something();
};
static B my_personal_B;
};
Finally, there's C's implementation file, C.cpp, which contains my_personal_B's storage unit:
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
}
This pattern is repeated for a lot of classes, each having a nested class which inherits from A. This has all been operating flawlessly through several code revisions, but lately the application crashes with this specific error message:
Debug Assertion Failed!
Program:
[redacted].exe
File: f:\dd\vctools\crt_bld\self_x86\crt\src\dbgheap.c
Line: 1511
Expression: _CrtIsValidHeapPointer(pUserData)
If I click to debug, I'm shown the line in C.cpp, where the static member is defined.
This doesn't seem like a static fiasco, because nothing static refers to my_personal_B, neither A nor B have anything but default constructors, and therefore couldn't possibly be referring to some other not-yet-initialized static object. The way I understood the fiasco is that it happened when one static object referred to another not-yet-initialized static object.
Nevertheless, if I change the static member to an initialize-on-first-use method, the crash seems to go away.
So the question is, why is this crashing?
해결책
Class A has virtual functions. What that means is that the compiler produces a static object called a vtable to hold pointers to member functions. So although you did not define any static objects in class A, the compiler must do so. Class B depends on that vtable (for A's virtual destructor, if nothing else). Apparently the initialization code is now trying to create an object of type B before A's vtable is constructed.
다른 팁
Dude, why are you relying on static initialization in the first place? Can you say "design error"?
SUGGESTION:
If you can't change the design, at least be sure to set a flag "bInitialized" so dependent clients can check whether or not your object has actually be initialized, and fail gracefully.
IMHO...