2

I'm creating a c++ project using the Embarcadero RAD Studio XE7 compiler. In this project I have the following code design:

  • A main form, inheriting from TForm, which contains a destructor
  • A class "foo"
  • A class "bar" in which the class "foo" is a static member

Now from the main form destructor I need to execute a function contained in the foo class. So in my main form destructor I've placed a code like this:

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

However my application crash at this point, in my case with a "Pure virtual function called" error (this error is of course dependent of my implementation, I will not enter in details here). The fact is that my Bar::m_Foo class was deleted before the TForm1 destructor.

To outline the issue, I recreated a minimal code example here:

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.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

Class.cpp

#include "Class.h"

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

Once executed, the above code shows the following result:

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

This underline that the static member destructor is called BEFORE the main form destructor, letting thus any usage of the Foo class hazardous in my TForm1 destructor. This result let me a little puzzled, because I always trusted that a static member variable became out of scope on the same time the application exited, i.e. AFTER the call of my main form destructor. But it's seems that it's not the case.

So my questions are:

  • What are the rules about such static members and when they become out of scope?
  • Why my Foo destructor is called before the main form destructor?
  • Is this destruction order defined in the c++ standards or is it a RAD Studio bug instead?
  • The function called by the form destructor is used in my case to release a global GDI+ instance. As I use GDI+ in a shared context (a main exe PLUS a dll), the main form call may release the final lock, or not. For that reason the static keyword is important here. But am I doing something wrong? Which design could be better?

------------------------- EDIT ---------------------------------

Here is also the code of the app main entry point of the above example, where the TForm1 is created and deleted:

#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;
}
//---------------------------------------------------------------------------
Jean-Milost Reymond
  • 1,833
  • 1
  • 15
  • 36

1 Answers1

1

I finally found the reason why my static member destructor is called before my main form destructor. This is due to a property specific to the Embarcadero RAD Studio compilers.

In fact, the compiler generates some automatic code when a new project is created. In this code (and as it can be seen on the above posted samples), the main form is created and kept inside another object named Application, which is... a static global object.

Here is how the Application object is declared in the RAD Studio VCL:

...

{ Global objects }

var
  Application: TApplication;

...

Of course, in these conditions, the main form object become dependent of the destruction of his parent, and because it is a static object, it can be destroyed randomly while all the static objects become out of scope while the application terminates.

And this also explain why it is an error to call a static member function from inside the main form destructor, which, in my case, caused a so strange access violation.

Jean-Milost Reymond
  • 1,833
  • 1
  • 15
  • 36