Delphi类def导致EStackOverflow

use*_*073 1 delphi destructor class

我有一个使用类的应用程序,一个名为TBaseDB的基类,并且会有许多TBaseDB的后代,所有DIRECT兄弟,现在只有一个已经启动,TOraDB,但稍后会添加TSQLDB等.

我的应用程序使用该类的一个实例,它是一个全局实例,即一个名为PROJ的全局变量.我对构造函数,析构函数和全局变量的理解存在一个问题,它导致EStackOverflow在应用程序的其他位置.如果我注释掉我的PROJ.CREATE,EStackOverflow就会消失.

我的构造函数只能设置变量,它们不会动态创建链表,数组或其他内存密集型对象.

以下是一些代码段.

// global var definition
// Specifically of BASE class, so I can call any child class without knowing which child class it is...
PROJ : TBaseDB;
Run Code Online (Sandbox Code Playgroud)

我的例程导致我的错误......

procedure TForm1.ShowBug;
begin
  // We have clicked on 'Create New Oracle Project

  // Now create our PROJ object.
  // This is defined globally, but MAY have been used before
  // so 'zero' it out
 FreeAndNil(PROJ);
 // Note that the create is on the CHILD class, not the BASE class
 // If I DON'T create the class, no error.... 
 PROJ := TOraDB.Create;

 // ... other code
end;
Run Code Online (Sandbox Code Playgroud)

这是我的课程定义.

Type
  TBaseDB = class
  published    
  public

    DAC_ID: Integer;
    DAC_ShortName : String;
    DAC_LongName: String;

    Constructor Create;
    Destructor Destroy; override;
    ... other stuff
  end;

implementation


// TBaseDB /////////////////////////////////////////////////////////////////
constructor TBaseDB.Create;
begin
  inherited;
end;

destructor TBaseDB.Destroy;
begin
 // If I comment out next two lines, my issue goes away
 // but shouldn't I have them....?  
  Self.Free;
  Self := nil;

  // Always call the parent destructor after running your own code
  inherited;
end;
Run Code Online (Sandbox Code Playgroud)

这是我对TOraDB类的定义

Type
  TOraDB = Class(TBaseDB)
  public
    Constructor Create;
    Destructor Destroy; override;
   ... other stuff
  End;

implementation

// ------------------------------------------------------------------------------
constructor TOraDB.Create;
begin
  inherited;

  // Now set up the information about the source database.  We know it is Oracle
  // even though we DONT know if it is connected
  DAC_ID := 4;
  DAC_ShortName := 'Ora';
  DAC_LongName := 'Oracle';
end;

// -----------------------------------------------------------------------------
destructor TOraDB.Destroy;
begin
  // Always call the parent destructor after running your own code
  inherited;
end;
Run Code Online (Sandbox Code Playgroud)

我不了解'重置'全局类变量.我应该在哪里'重置它,所以我仍然可以使用GLOBAL变量PROJ?

谢谢,

GS

Sir*_*ufo 12

你不能Self.Free在类的析构函数中调用.

免费调用Destroy and Destroy calls Free ......直到Stack Overflow

destructor TBaseDB.Destroy;
begin

  // Don't do that at all in a destructor

  // Self.Free;
  // Self := nil;

  // Always call the parent destructor after running your own code
  inherited;
end;
Run Code Online (Sandbox Code Playgroud)

TObject.Free 只是对析构函数的安全调用,因为它将测试Instance是否为零.

procedure TObject.Free;
begin
  if Self <> nil then
    Destroy;
end;
Run Code Online (Sandbox Code Playgroud)

编辑

关于全局变量,PROJ有一个简单(但不是非常明智)的解决方案

destructor TBaseDB.Destroy;
begin

  if Self = PROJ then
    PROJ := nil;

  // Always call the parent destructor after running your own code
  inherited;
end;
Run Code Online (Sandbox Code Playgroud)

您应该看一下Singleton实现.

  • @ user1009073是的,但只是在你的析构函数中继承,根本不需要派生的析构函数 (2认同)
  • 简单的规则是构造函数中的每个`FObj:= TSomeObject.Create`都要与析构函数中的`FObj.Free`配对.并按照与创建顺序相反的顺序释放它们. (2认同)