2012-09-28 2 views
1

정적 초기화에서 크래시 (디버그 어설 션 오류 : VC++ 2008의 CRT 힙 포인터가 유효하지 않음)가 발생하며 그 이유를 모르겠습니다.C++ 정적 초기화 실패가 클래스 계층에 적용됩니까?

나는 C++ FAQ에서 static initialization fiasco에 관한 모든 것을 읽었으며, 나는 그것에 대해 이해하고 있다고 생각했다. 왜 이런 일이 일어나고 있는지, 왜 그것이 대 실패의 경우인지 이해할 수 없다.

여기 상황이 있습니다 (대부분의 비 정적 구성원은 간략하게 생략되었습니다). I 아에 정의 된 하나 개의 클래스 A,이 : 다음

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

    virtual void do_something(); 
}; 

를 I 클래스는 하위 클래스가 C는, A. C의 서브 B도의 개인 고정 부재가 포함되어있다 타입 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 구현 파일 my_personal_B의 기억 부 포함 C.cpp,이 패턴은 클래스 많이 반복된다

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 
} 

가 각각 중첩 클래스를 갖는 어떤 상속 fr om A. 이것은 몇 가지 코드 개정을 통해 완벽하게 작동했지만 최근에는 다음과 같은 특정 오류 메시지와 함께 응용 프로그램이 충돌합니다.

디버그 어설 션 오류!

프로그램 :
[편집 됨]
.exe 파일 : F를 : \ DD \ vctools \ crt_bld \ self_x86 \ CRT \ SRC \ dbgheap.c
라인 : 1511

표현 : _CrtIsValidHeapPointer (pUserData)

디버깅하려면 클릭하면 정적 멤버가 정의 된 C.cpp 줄이 표시됩니다.

static은 아무 것도 my_personal_B를 참조하지 않기 때문에 A와 B는 기본 생성자 이외의 다른 값을 가지지 않으므로 아직 초기화되지 않은 다른 정적 객체를 참조 할 수 없습니다. 실패를 이해하는 방법은 한 정적 객체가 아직 초기화되지 않은 다른 정적 객체를 참조했을 때 발생한다는 것입니다.

정적 멤버를 첫 번째 사용 초기화 메서드로 변경하면 충돌이 사라지는 것처럼 보입니다.

문제는 왜 이렇게 충돌하는 것입니까?

+0

1. 언제 충돌합니까? 2. 호출 스택이란 무엇입니까? –

답변

2

클래스 A에는 가상 기능이 있습니다.즉, 컴파일러가 vtable이라는 정적 객체를 생성하여 멤버 함수에 대한 포인터를 보유합니다. 따라서 클래스 A에 정적 객체를 정의하지는 않았지만 컴파일러는이를 수행해야합니다. 클래스 B는 해당 vtable에 의존합니다 (A의 가상 소멸자의 경우). 명백히 초기화 코드는 A의 vtable이 생성되기 전에 B 유형의 객체를 생성하려고합니다.

+0

Ohhhhh, 알았어, 그게 말이야, 왜 내가 최근에 A까지 가상 소멸자 선언을 추가 할 때까지 심지어 나타나지 않았는 지 설명해. (이전에는 A 계층의 어떤 클래스도 소멸자를 가지고 있지 않았지만 그게 바뀌었다.) (저는 저예산가의 새로운 포스터이기 때문에 귀하의 회신을 취소 할 수 없습니다 ... 죄송합니다) –

-1

야, 왜 처음부터 정적 초기화를 사용하고 계십니까? "디자인 오류"라고 말할 수 있습니까?

SUGGESTION : 당신이 디자인을 변경할 수 없다면, 적어도 "bInitialized"플래그를 설정해야

때문에 종속 클라이언트는 개체가 실제로 초기화 여부를 확인할 수 있으며 정상적으로 실패합니다.

IMHO ...

+1

그건 의견이 아니라 대답입니다. –