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 

こうしてのFooクラスのいずれかの使用をさせる静的メンバデストラクタが前にメインフォームのデストラクタと呼ばれるこのアンダーライン、私のTForm1デストラクタで危険です。この結果は、アプリケーションが終了したときに静的メンバー変数が範囲外になったことを常に信頼していたため、私はちょっと困惑させました。つまり、AFTER私のメインフォームデストラクタの呼び出しです。しかし、それはそうではないようです。

だから私の質問は以下のとおりです。

  • な静的メンバとするとき、彼らがスコープ外になる程度のルールは何ですか?
  • 私のFooデストラクタがメインフォームデストラクタの前に呼び出されるのはなぜですか?
  • この破棄命令はC++標準で定義されていますか、代わりにRAD Studioのバグですか?
  • 私のケースでは、グローバルなGDI +インスタンスをリリースするために、フォームdestructorによって呼び出される関数が使用されています。 GDI +を共有コンテキスト(メインexe プラスDLL dll)で使用すると、メインフォーム呼び出しによって最終的なロックが解放されるかどうかが決まります。そのため、ここでは静的キーワードが重要です。しかし私は何か間違っているのですか?どのデザインが良いでしょうか?

------------------------- EDIT ------------------ ---------------ここ

もTForm1が作成され、削除されている上記の例のアプリメインエントリポイントのコードである:

#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

私は最終的に私の静的メンバーデストラクタがメインフォームデストラクタの前に呼び出される理由を見つけました。これは、Embarcadero RAD Studioコンパイラ特有のプロパティによるものです。

実際、新しいプロジェクトが作成されると、コンパイラによって自動コードが生成されます。このコードでは(そして上に掲載されたサンプルで見られるように)、メインフォームが作成され、Applicationという名前の別のオブジェクト(静的なグローバルオブジェクト)内に保持されます。ですので

もちろん
... 

{ Global objects } 

var 
    Application: TApplication; 

... 

は、これらの条件では、メインフォームオブジェクトは、彼の親の破壊の依存するようになる、と:ここでは

は、ApplicationオブジェクトがRAD StudioのVCLに宣言されている方法ですアプリケーションが終了している間にすべての静的オブジェクトが有効範囲外になる間に、ランダムに破棄することができます。

これはまた、私の場合、非常に奇妙なアクセス違反を引き起こしたメインフォームデストラクタの内部から静的メンバ関数を呼び出すのがなぜエラーであるかを説明しています。

関連する問題