Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

InstanceClass.NewInstance vs InstanceClass.Create

Tags:

oop

delphi

vcl

what different between InstanceClass.NewInstance+Instance.Create and InstanceClass.Create;

Method1:

Instance := TComponent(InstanceClass.NewInstance);
Instance.Create(Self);

Method2:

Instance := InstanceClass.Create(Self);

Which is better?

like image 829
MajidTaheri Avatar asked May 05 '12 10:05

MajidTaheri


3 Answers

I would always use InstanceClass.Create if it is appropriate – and invariably it is.

There are plenty of reasons. A very good one is that the single line version is more concise. Another is that the single line version is the standard, commonly used approach.

Yet another reason is the handling of exceptions in the constructor which your method 1 does not manage correctly. In case of an exception, the new instance will be destroyed, but the instance variable has still been assigned to. That's an important difference from method 2 and goes against all the lifetime management conventions of Delphi.

You mention TApplication.CreateForm. Let's take a look at it:

Instance := TComponent(InstanceClass.NewInstance);
TComponent(Reference) := Instance;
try
  Instance.Create(Self);
except
  TComponent(Reference) := nil;
  raise;
end;

Remember that Reference is the form variable that you pass as a var parameter. The point about this is this code assigns that form variable before calling the constructor. Normally that assignment is only made after the constructor completes.

Presumably this is so that code which references the form variable (often a global variable) can work even if it is invoked from inside that form's constructor. This is a very special case and is overwhelmingly the exception rather than the rule. Don't let this special case drive your mainstream coding style.

like image 76
David Heffernan Avatar answered Sep 22 '22 12:09

David Heffernan


(I added this answer, because IMHO others where not complete)

Method 2 is the correct one.

Method 1 if never to be called, since there is an hidden parameter to the constructor call, which may fail proper iniatialize: in fact, NewInstance is a per-class pseudo virtual method!

In fact, there is an hidden boolean parameter at constructor call (register EDX, since EAX=class). As stated by official documentation:

Constructors and destructors use the same calling conventions as other methods, except that an additional Boolean flag parameter is passed to indicate the context of the constructor or destructor call.

A value of False in the flag parameter of a constructor call indicates that the constructor was invoked through an instance object or using the inherited keyword. In this case, the constructor behaves like an ordinary method. A value of True in the flag parameter of a constructor call indicates that the constructor was invoked through a class reference. In this case, the constructor creates an instance of the class given by Self, and returns a reference to the newly created object in EAX.

In particular, when called that way, the class won't call the _ClassCreate function. It may fail to initialize the class, if the class is not to be created with the default NewInstance function. In fact, this function is inserted into the class VMT: in some rare cases, it may be overloaded (e.g. to provide another memory allocation pattern - may be a garbage collector or some speed-optimized allocator). So calling directly InstanceClass.NewInstance can be buggy, in some border cases.

function _ClassCreate(AClass: TClass; Alloc: Boolean): TObject;
asm
  ...
    TEST    DL,DL
    JL      @@noAlloc
    CALL    dword ptr [EAX].vmtNewInstance
@@noAlloc:
  ...

Therefore, calling InstanceClass.NewInstance directly is only to be done on purpose, only if you want to cancel two overridden vmtNewInstance / vmtFreeInstance (and in this case, you may have to also NOT call .Free / .Destroy, but you own memory free function). So: never call NewInstance, but the constructor, as designed and documented by Embarcadero (and FreePascal team by the way), unless you need to make some internal low-level tweak.

NEVER use method 1 to create an object! It may work 99.9 % of the time, but may fail some cases, or with a compiler/RTL enhancement in the future (like a garbage collector). Even if the VCL sometimes uses NewInstance, you should not use it - I would rather prefer this method to be made protected.

like image 37
Arnaud Bouchez Avatar answered Sep 22 '22 12:09

Arnaud Bouchez


Second is better because it is a standard method to create a class instance, while procedural form should be used within constructor to call inherited constructor.

like image 28
kludg Avatar answered Sep 21 '22 12:09

kludg