2013-03-05 63 views
1

我有一个使用类的应用程序,叫做TBaseDB一个基类,而且会有TBaseDB的多子多孙,所有直接兄弟姐妹,只有一个已经现在开始,TOraDB,但之后会添加TSQLDB和其他。德尔福级高清造成EStackOverflow

我的应用程序使用类的一个实例,它是一个全球性的实例,即所谓的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; 

我的例行这将导致我的错误...

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; 

这里是我的类定义。

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; 

这里是我的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; 

我不理解一些有关“重置”全局类变量定义。我应该在哪里重置它,所以我仍然可以使用GLOBAL变量PROJ?

感谢,

GS

回答

12

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

免费拨打销毁和销毁电话免费......直到堆栈溢出

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; 

TObject.Free是析构函数的只是一个安全通话,因为它会测试该实例不是零。

procedure TObject.Free; 
begin 
    if Self <> nil then 
    Destroy; 
end; 

编辑

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

destructor TBaseDB.Destroy; 
begin 

    if Self = PROJ then 
    PROJ := nil; 

    // Always call the parent destructor after running your own code 
    inherited; 
end; 

你应该看看辛格尔顿实现来代替。

+0

所以,如果我没有创建任何“特殊”内存对象不仅仅是基础串等,等,被调用INHERITED足够了吗?即INHERITED -all-我需要在析构函数中? – user1009073 2013-03-05 13:14:30

+2

@ user1009073是的,不过话说只有在你的析构函数继承,就没有必要对派生的析构函数在所有 – 2013-03-05 13:17:16

+2

简单的规则是每'FObj:= TSomeObject。在你的构造函数中创建''''与析构函数中的'FObj.Free'配对。并按照创建顺序的相反顺序释放它们。 – 2013-03-05 13:21:31

2

不要使用:

Self.Free; 
    Self := nil; 

在你的析构函数。

+0

Rufo爵士殴打:-( – 2013-03-05 12:53:17

+1

这不是一个“不需要”,它根本就是错的 – 2013-03-05 12:59:39

+0

@Sir Rufo,你说过*“不应该”*,但更好用*“绝对不能” *在你的答案中* *“不应该”*给你仍然有一些自由去做 – TLama 2013-03-05 13:13:29