bcc32和bcc32c对象生存期之间的差异

时间:2016-06-13 06:48:24

标签: c++ clang c++builder firemonkey object-lifetime

我有一个使用C ++ Builder 10.1 Berlin的跨平台C ++应用程序构建,并且在理解对象的生命周期处理方面存在问题,在这种情况下,字符串是在类外声明的。 我创建了一个新的表单应用程序并添加了一些代码。 cpp文件如下所示:

#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);
}

我用CLANG增强的C ++ 11编译器bcc32c编译它,运行应用程序并再次关闭表单。当调用TForm1 :: FormDestroy时,Hello已经被破坏了。当我使用经典编译器bcc32编译win32的代码时,字符串在FormDestroy之后被销毁。

有人可以解释一下或提供一些有关我必须寻找的主题的信息吗?为什么基于CLANG的编译器在这里表现不同?

修改

当我使用自定义类而不是字符串时,它更容易调试。

class Foo {
public:
   Foo(){};
  ~Foo(){}
};
Foo A;

//--------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
}
//--------------------------------------------------------------------------

__fastcall TForm1::~TForm1()
{
}

创造和破坏就像这样。我添加了调用堆栈。

bcc32c(CLANG C ++ 11编译器)

  1. 创建Foo

      

    :004052C0 Foo(this =:00400000)
      :00405070 __cxx_global_var_init3()
      :004052A3 _GLOBAL__I_a()
      :00405ab7; 〜富
      :321fa2b7; C:\ Program Files(x86)\ Embarcadero \ Studio \ 18.0 \ bin \ CC32C240MT.DLL
      :321fa6ff CC32C240MT .__ wstartup + 0xbb

  2. 创建Form1

      

    :004052EC TForm1(此=:00402422,__ vector_flag =' \ 0')
      :0085c139 fmx240。@Fmx @ Forms @ TApplication @ CreateForm $ qqrxp17System @ TMetaClasspv + 0x5d
      :0085c349 fmx240。@Fmx @ Forms @ TApplication @ RealCreateForms $ qqrv + 0x81

  3. 摧毁Foo

      

    :004052D0~Foo(this =:0040B7DC)
      :0040509E __dtor_A()
      :321f6246 CC32C240MT .___ call_atexit_procs + 0x52
      :321f671c CC​​32C240MT .___退出+ 0x20

  4. 销毁Form1

      

    :00405868~TForm1(this =:5016E698)

  5. bcc32(经典borland编译器)

    1. 创建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 + 0xa5

    2. 创建Form1

        

      :00404994 TForm1 :: TForm1(此=:02F2AE20,所有者=:02F39620)
        :0095c139 fmx240。@Fmx @ Forms @ TApplication @ CreateForm $ qqrxp17System @ TMetaClasspv +   0x5d
        :0095c349 fmx240。@Fmx @ Forms @ TApplication @ RealCreateForms $ qqrv + 0x81

    3. 销毁Form1

        

      :00404ABC TForm1 :: ~TForm1(this =:02F2AE20)

    4. 摧毁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

1 个答案:

答案 0 :(得分:3)

自动创建的TForm对象归全局TApplication对象所有。在应用程序的main() / wmain() / WinMain()入口点函数退出后,该对象被销毁(从而销毁其拥有的表单)。在应用程序清理期间销毁Globals。

在任一编译器中,全局String的生命周期保证不会超过全局TApplication对象的生命周期。您基于不同单位的全局变量的清理顺序依赖于未定义的行为。更糟糕的是,您依赖于不同框架的清理顺序!您的String位于您自己的C ++代码中,但TApplication对象位于基于Delphi的RTL库中。

如果String需要在使用它的TForm的生命周期内保持活跃状态​​,则应将其声明为该类的static成员:

FmrMain.h:

//---------------------------------------------------------------------------

#ifndef FmrMainH
#define FmrMainH
//---------------------------------------------------------------------------
#include <System.Classes.hpp>
#include <FMX.Controls.hpp>
#include <FMX.Forms.hpp>
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published:    // IDE-managed Components
private:    // User declarations
    static const String Hello;
public:     // User declarations
    __fastcall TForm1(TComponent* Owner);
    __fastcall ~TForm1();
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif

FmrMain.cpp:

//---------------------------------------------------------------------------
#include <fmx.h>
#pragma hdrstop

#include "FmrMain.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.fmx"
TForm1 *Form1;

const String TForm1::Hello = "Hello";
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
    ShowMessage(Hello);
}

void __fastcall TForm1::~TForm1()
{
    ShowMessage(Hello);
}
//---------------------------------------------------------------------------

或者,使用wchar_t*代替String,然后您就不会遇到任何清理问题:

//---------------------------------------------------------------------------
#include <fmx.h>
#pragma hdrstop

#include "FmrMain.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.fmx"
TForm1 *Form1;

static const wchar_t* Hello = L"Hello";
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
    ShowMessage(Hello);
}

void __fastcall TForm1::~TForm1()
{
    ShowMessage(Hello);
}
//---------------------------------------------------------------------------