I have a cross platform C++ application build with C++ Builder 10.1 Berlin and have a problem understanding the lifetime handling of objects, in this case strings, wich are declared outside the class. I have created a new forms application and added some code. The cpp file looks like this:
#include
#pragma hdrstop
#include "FmrMain.h"
#pragma package(smart_init)
#pragma resource "*.fmx"
TForm1 *Form1;
const String Hello = "Hello";
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
ShowMessage(Hello);
}
void __fastcall TForm1::FormDestroy(TObject *Sender)
{
ShowMessage(Hello);
}
I compile this with the CLANG enhanced C++11 compiler bcc32c, run the application and close the form again. When TForm1::FormDestroy is called Hello is allready destroyed. When I compile the code for win32 with the classic compiler bcc32 the string is destroyed after FormDestroy.
Can someone explain this or provide some information about the topics I have to look for? Why is the CLANG based compiler behaving different here?
Edit
It's easier to debug when I use a self defined class instead of a string.
class Foo {
public:
Foo(){};
~Foo(){}
};
Foo A;
//--------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
}
//--------------------------------------------------------------------------
__fastcall TForm1::~TForm1()
{
}
The creation and destruction oder is like this. I have added the call stacks.
bcc32c (CLANG C++11 compiler)
create Foo
:004052C0 Foo(this=:00400000)
:00405070 __cxx_global_var_init3()
:004052A3 _GLOBAL__I_a()
:00405ab7 ; ~Foo
:321fa2b7 ; C:\Program Files (x86)\Embarcadero\Studio\18.0\bin\CC32C240MT.DLL
:321fa6ff CC32C240MT.__wstartup + 0xbbcreate Form1
:004052EC TForm1(this=:00402422, __ctor_flag='\0')
:0085c139 fmx240.@Fmx@Forms@TApplication@CreateForm$qqrxp17System@TMetaClasspv + 0x5d
:0085c349 fmx240.@Fmx@Forms@TApplication@RealCreateForms$qqrv + 0x81destroy Foo
:004052D0 ~Foo(this=:0040B7DC)
:0040509E __dtor_A()
:321f6246 CC32C240MT.___call_atexit_procs + 0x52
:321f671c CC32C240MT.___exit + 0x20destroy Form1
:00405868 ~TForm1(this=:5016E698)
bcc32 (Classic borland compiler)
create Foo
:00404950 Foo::Foo(this=:00409B74)
:004048A0 STCON0()
:00405727 ; IRoot
:322190f1 ; C:\Program Files (x86)\Embarcadero\Studio\18.0\bin\CC32240MT.DLL > :322193b5 CC32240MT.__wstartup + 0xa5create Form1
:00404994 TForm1::TForm1(this=:02F2AE20, Owner=:02F39620)
:0095c139 fmx240.@Fmx@Forms@TApplication@CreateForm$qqrxp17System@TMetaClasspv + 0x5d
:0095c349 fmx240.@Fmx@Forms@TApplication@RealCreateForms$qqrv + 0x81destroy Form1
:00404ABC TForm1::~TForm1(this=:02F2AE20)
destroy Foo
:00404978 Foo::~Foo(this=:00409B74)
:0040493F STDES0()
:0040573f ;IRoot>
:3221910f ; C:\Program Files(x86)\Embarcadero\Studio\18.0\bin\CC32240MT.DLL
:3221915b ; C:\Program Files (x86)\Embarcadero\Studio\18.0\bin\CC32240MT.DLL > :3221944a ; C:\Program Files (x86)\Embarcadero\Studio\18.0\bin\CC32240MT.DLL
const String Hellois a const object. It should not be destroyed before the main function returned. Probably It has never been created and the compiler has created a string constant instead that was sufficient as the argument to theShowMessagefunction. You can use a debugger to check this. - harperTObject-derived classes, includingTForm, are always allocated on the heap. In your example, theStringis in global memory and is being deallocated by the compiler before the RTL destroys the globalTApplicationobject that owns yourTForm1object. IOW, yourTForm1is outliving yourString, that is why it is NULL in yourOnDestroyevent handler (which BTW, you should NEVER BE USING IN C++! Use the~TForm1destructor instead). - Remy Lebeau