Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Delphi raise exception in constructor

Tags:

delphi

SITUATION

I am going to write a class and the constructor is a custom one that I have made because I need to initialize some values. This is the code I've written so far:

type
 TCombinatorio = class(TObject)
  private
   valN, valK: integer;
   result: double;
  public
   property K: integer read valK;
   property N: integer read valN;
   constructor Create(valN: integer; valK: integer);
 end;

constructor TCombinatorio.Create(valN: Integer; valK: Integer);
begin
  inherited Create;
   Self.valN := valN;
   Self.valK := valK;

  if ((valN < 0) or (valK < 0)) then
   begin
    raise Exception.Create('N and K must be >= 0');
   end;

end;

Since I am going to do some math calculations, I need to avoid negative numbers.


QUESTION

Can I raise an exception in the constructor in that way? I am running the code in this way:

procedure TForm1.Button1Click(Sender: TObject);
var a: TCombinatorio; 
    b: string;   
begin

 a := TCombinatorio.Create(5,-2);

 try
  //some code
 finally
  a.Free; 
 end;

end;

As you can see here I have wrong parameters for my constructor, since the second is negative. I also cannot understand (according with the code of my constructor) if the a.Free inside the finally is really needed because when the constructor raises the exception, the destructor is called.

I thought to include the a := TCombinatorio.Create(5,-2); inside the try-finally block to avoid the problem but I am not sure. What do you think?

like image 869
Alberto Miola Avatar asked Aug 23 '16 20:08

Alberto Miola


People also ask

How do I raise an exception in Delphi?

Raise Exception. Create('Error happened'); Version 3 As for version 2, but overriding the address value of the exception. In all cases, when the raise call is made, code execution jumps to the Delphi exception handler - it either terminates the program, or uses the current Try statement to handle it.

What is constructor in Delphi?

A constructor is a special kind of method. If you call a constructor using a class reference, Delphi creates a new instance of that class, initializes the instance, and then calls the constructor proper. If you call a constructor using an object reference, Delphi calls the constructor as an ordinary method.


1 Answers

Your code is absolutely fine and correct. Raising exceptions from constructors is perfectly respectable. As you know the destructor is called.

You ask about this code:

a := TCombinatorio.Create(5,-2);
try
  //some code
finally
  a.Free; 
end;

You are worried that Free will be called after the object has already been destroyed. That cannot happen. If an exception is raised in the constructor then it propagates up the call stack. That happens before the try block begins and so the finally block does not execute. Indeed the assignment to a does not happen.

Moving the creation inside the try would be disastrous and is in fact an incredibly common mistake. Suppose you did that:

// WARNING THIS CODE IS DEFECTIVE 
try
  a := TCombinatorio.Create(5,-2);
  //some code
finally
  a.Free; 
end;

Now if an exception is raised then Free is called but on what? The variable a is not initialized. Even if it was, which it isn't, that would still be a double free.

like image 122
David Heffernan Avatar answered Oct 08 '22 19:10

David Heffernan