Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I do some initializations before `Inherited Create`?

I want to create and start a thread, all with one command line TClientCopyThread.Create(...). For this, I must create the thread with Suspended = False, so that it can run immediately. I know that when I write a constructor of a new object, first of all I must call the inherited Create so that the instance of the object is created, and then do my initializations. But here, if I call inherited the thread will start without initialized parameters. I try to call inherited last and it seems it's working (I don't receive any access violation), but I don't know for sure if this is a coincidence or not.

  TClientCopyThread = class(TThread)
  private
    OwnGUID: String;
    SrcPath, DestPath: String;
    Files: TFileNames;
    RemoveIt: Boolean;
  protected
    procedure Execute; override;
  public
    constructor Create(const GUID, ASrcPath, ADestPath: String;
     const FileNames: TFileNames; RemoveSrc: Boolean);
  end;

constructor TClientCopyThread.Create(const GUID, ASrcPath, ADestPath: String;
 const FileNames: TFileNames; RemoveSrc: Boolean);
var I: Integer;
begin
 SrcPath:=  Copy(ASrcPath, 1, Length(ASrcPath));
 DestPath:= Copy(ADestPath, 1, Length(ADestPath));
 SetLength(Files, Length(FileNames));
 for I:= 0 to High(Files) do
  Files[I]:= Copy(FileNames[I], 1, Length(FileNames[I]));
 RemoveIt:= RemoveSrc;
 FreeOnTerminate:= True;
 inherited Create;
end;
like image 858
Marus Gradinaru Avatar asked Dec 05 '25 06:12

Marus Gradinaru


1 Answers

To answer your specific question - YES, you can call inherited Create at any point during a derived constructor. It DOES NOT need to be the first statement (same with inherited Destroy as the last statement in the destructor). Memory for the class object has already been allocated in full before any constructors are called, so it is safe to initialize members of your derived class before calling the inherited constructor. However, when accessing base class members from the derived constructor, you should call the inherited constructor first to initialize them before accessing them.

That being said, your understanding of how the TThread constructor works is just plain wrong. Since Delphi 6 onwards, the base class TThread constructor always creates the underlying OS thread in suspended mode, and then resumes the thread in TThread.AfterConstruction() after all constructors have fully exited, if the TThread object is constructed with CreateSuspended=False. So, your claim that calling inherited Create with CreateSuspended=False will start the thread running immediately has NOT been true since 2001 when Delphi 6 was released. The underlying OS thread will NOT start running until after your TClientCopyThread.Create() constructor has exited. Thus, your Execute() method will never act on uninitialized members, regardless of how you set CreateSuspended.

What you describe (the thread running before members were initialized) was a bug in Delphi 5 and earlier, which was fixed in Delphi 6.

like image 60
Remy Lebeau Avatar answered Dec 08 '25 01:12

Remy Lebeau