Я создаю проект С++ с помощью компилятора Embarcadero RAD Studio XE7. В этом проекте у меня есть следующий дизайн кода:
- Основная форма, унаследованная от TForm, содержащая деструктор
- Класс "фу"
- Класс "bar", в котором класс "foo" является статическим членом.
Теперь из деструктора основной формы мне нужно выполнить функцию, содержащуюся в классе foo. Итак, в моем деструкторе основной формы я разместил такой код:
__fastcall TForm1::~TForm1()
{
Bar::m_Foo.ExecuteSomething();
}
Однако в этот момент мое приложение вылетает, в моем случае с ошибкой «Вызывается чистая виртуальная функция» (эта ошибка, конечно, зависит от моей реализации, я не буду вдаваться в подробности здесь). Дело в том, что мой класс Bar::m_Foo был удален до деструктора TForm1.
Чтобы обозначить проблему, я воссоздал здесь минимальный пример кода:
Основной.ч
#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;
}
//---------------------------------------------------------------------------
Класс.h
#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
Класс.cpp
#include "Class.h"
//---------------------------------------------------------------------------
Foo Bar::m_Foo;
//---------------------------------------------------------------------------
После выполнения приведенный выше код показывает следующий результат:
Foo constructor - CALLED
TForm1 constructor - CALLED
Foo destructor - CALLED
TForm1 destructor - CALLED
Это подчеркивает, что деструктор статического члена вызывается ДО основного деструктора формы, что делает любое использование класса Foo опасным в моем деструкторе TForm1. Этот результат заставил меня немного озадачиться, потому что я всегда верил, что статическая переменная-член выходит из области видимости в то же время, когда приложение закрывается, то есть ПОСЛЕ вызова деструктора моей основной формы. Но похоже, что это не так.
Итак, мои вопросы:
- Каковы правила для таких статических членов и когда они выходят за рамки?
- Почему мой деструктор Foo вызывается перед деструктором основной формы?
- Определен ли этот порядок уничтожения в стандартах С++ или это ошибка RAD Studio?
- В моем случае функция, вызываемая деструктором формы, используется для освобождения глобального экземпляра GDI+. Поскольку я использую GDI+ в общем контексте (основной exe ПЛЮС dll), вызов основной формы может снять окончательную блокировку или нет. По этой причине ключевое слово static здесь важно. Но я делаю что-то не так? Какой дизайн может быть лучше?
------------------------- РЕДАКТИРОВАТЬ ------------------------ ---------
Вот также код основной точки входа приложения из приведенного выше примера, где создается и удаляется 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;
}
//---------------------------------------------------------------------------
Form1
? Как создается и уничтожаетсяTForm1
? - person Alan Stokes   schedule 18.11.2017