2017-11-18 4 views
2

Embarcadero RAD Studio XE7 컴파일러를 사용하여 C++ 프로젝트를 만들고 있습니다. 이 프로젝트에서 다음 코드 디자인이 : 소멸자를 포함 TForm 클래스, 상속,C++ - 파괴 순서 - 메인 클래스 소멸자보다 먼저 함수의 정적 멤버가 소멸됩니다.

  • 기본 폼을
  • 클래스 "foo는"
  • 클래스 "바"어떤 클래스 "에 foo "정적 멤버입니다

이제 주 양식 소멸자에서 foo 클래스에 포함 된 함수를 실행해야합니다. 내 기본 폼의 소멸자에서 나는 다음과 같은 코드를 삽입 한 그래서 :

__fastcall TForm1::~TForm1() 
{ 
    Bar::m_Foo.ExecuteSomething(); 
} 

그러나 오류 (이 오류에 "라는 순수 가상 함수"내 경우에는이 시점에서 내 응용 프로그램의 충돌, 의존 물론입니다 내 구현, 난 여기에 세부 사항을 입력하지 않습니다). 사실, Bar :: m_Foo 클래스는 TForm1 소멸자보다 먼저 삭제되었습니다.

#ifndef AClassH 
#define AClassH 

#include <Windows.h> 

class Foo 
{ 
    public: 
     Foo() 
     { 
      std::cout << "Foo constructor - CALLED" << std::endl; 
     } 

     virtual ~Foo() 
     { 
      std::cout << "Foo destructor - CALLED" << std::endl; 
     } 
}; 

class Bar 
{ 
    private: 
     static Foo m_Foo; 
}; 

#endif 
Class.h

Main.h

#ifndef MainH 
#define MainH 

#include <System.Classes.hpp> 
#include <Vcl.Controls.hpp> 
#include <Vcl.StdCtrls.hpp> 
#include <Vcl.Forms.hpp> 

class TForm1 : public TForm 
{ 
    __published: 

    public: 
     __fastcall TForm1(TComponent* Owner); 
     virtual __fastcall ~TForm1(); 

    private: 
}; 
extern PACKAGE TForm1 *Form1; 
#endif 

하여 Main.cpp

#include <vcl.h> 
#pragma hdrstop 
#include "Main.h" 

#include <iostream.h> 

#pragma package(smart_init) 
#pragma resource "*.dfm" 

//--------------------------------------------------------------------------- 
TForm1 *Form1; 
//--------------------------------------------------------------------------- 
__fastcall TForm1::TForm1(TComponent* Owner) 
    : TForm(Owner) 
{ 
    std::cout << "TForm1 constructor - CALLED" << std::endl; 
} 
//--------------------------------------------------------------------------- 
__fastcall TForm1::~TForm1() 
{ 
    std::cout << "TForm1 destructor - CALLED" << std::endl; 
} 
//--------------------------------------------------------------------------- 

:

문제를 간략하게 설명하기 위해, 나는 여기에 최소한의 코드 예제를 다시

Class.cpp

#include "Class.h" 

//--------------------------------------------------------------------------- 
Foo Bar::m_Foo; 
//--------------------------------------------------------------------------- 

일단 실행은, 위의 코드는 다음과 같은 결과를 보여줍니다

Foo constructor - CALLED 
TForm1 constructor - CALLED 
Foo destructor - CALLED 
TForm1 destructor - CALLED 

따라서 푸 클래스의 사용을시키는 정적 멤버 소멸자가 전에 기본 폼의 소멸자 호출이 밑줄, 내 TForm1 소멸자에서 위험합니다. 이 결과는 응용 프로그램이 종료 될 때 정적 멤버 변수가 범위를 벗어난 것으로 항상 믿었 기 때문에 (예 : , 이후) 내 기본 폼 소멸자 호출이 신뢰할 수 없기 때문에 조금 혼란 스러웠습니다. 그러나 그것이 사실이 아닌 것처럼 보입니다. 그들이 범위를 벗어난 될 때

  • 는 정적 멤버에 대한 규칙 무엇과 :

    그래서 내 질문은?

  • 내 Foo 소멸자가 주 양식 소멸자보다 먼저 호출되는 이유는 무엇입니까?
  • 이 파괴 명령은 C++ 표준에 정의되어 있습니까? 아니면 RAD Studio 버그입니까?
  • 소멸자 형태로 호출되는 함수는 필자의 경우 전역 GDI + 인스턴스를 해제하는 데 사용됩니다. 공용 컨텍스트 (주 EXE PLUS dll)에서 GDI +를 사용하면 주 양식 호출이 최종 잠금을 해제 할 수 있습니다. 이러한 이유로 정적 키워드가 중요합니다. 하지만 내가 뭔가 잘못하고있는거야? 어떤 디자인이 더 좋을까요?

------------------------- 편집 ------------------

#include <vcl.h> 
#pragma hdrstop 
#include <tchar.h> 
//--------------------------------------------------------------------------- 
USEFORM("Main.cpp", Form1); 
//--------------------------------------------------------------------------- 
int WINAPI _tWinMain(HINSTANCE, HINSTANCE, LPTSTR, int) 
{ 
    try 
    { 
     Application->Initialize(); 
     Application->MainFormOnTaskBar = true; 
     Application->CreateForm(__classid(TForm1), &Form1); 
     Application->Run(); 
    } 
    catch (Exception &exception) 
    { 
     Application->ShowException(&exception); 
    } 
    catch (...) 
    { 
     try 
     { 
      throw Exception(""); 
     } 
     catch (Exception &exception) 
     { 
      Application->ShowException(&exception); 
     } 
    } 
    return 0; 
} 
//--------------------------------------------------------------------------- 
+1

여기서'Form1'은 어떻게 할당 되나요? 'TForm1'은 어떻게 생성되고 파괴됩니까? –

+0

좋은 발언. 게시 됨, 감사합니다. –

답변

1

: ---------------

여기

또한 된 TForm1 생성 및 삭제 위의 예제의 응용 프로그램의 주요 진입 점의 코드 내 정적 멤버 소멸자가 내 주 양식 소멸자보다 먼저 호출되는 이유를 마침내 발견했습니다. 이는 Embarcadero RAD Studio 컴파일러 고유의 속성 때문입니다.

실제로 컴파일러는 새 프로젝트가 만들어지면 자동 코드를 생성합니다. 이 코드에서 (그리고 위에 게시 된 샘플에서 볼 수 있듯이) 메인 폼은 Application이라는 다른 객체 (정적 전역 객체) 내에 만들어지고 유지됩니다. 그것은을하기 때문에

물론
... 

{ Global objects } 

var 
    Application: TApplication; 

... 

는, 이러한 조건에서, 기본 폼 객체가 자신의 부모의 파괴 의존하고, 다음은

는 Application 개체가 RAD 스튜디오 VCL에 선언하는 방법입니다 정적 객체 인 경우 응용 프로그램이 종료되는 동안 모든 정적 객체가 범위를 벗어나는 동안 무작위로 파괴 될 수 있습니다.

그리고 이것은 왜 내 경우에 너무 이상한 액세스 위반을 일으키는 주 양식 소멸자 내부에서 정적 멤버 함수를 호출하는 것이 오류라고 설명합니다.

관련 문제