Should I put a try-finally block after each Object.Create?

I have a general question about best practice at OO Delphi. Currently, I put try-finally blocks anywhere I create an object to free this object after use (to avoid memory leaks). For example:.

aObject := TObject.Create; try aOBject.AProcedure(); ... finally aObject.Free; end; 

instead:

 aObject := TObject.Create; aObject.AProcedure(); .. aObject.Free; 

Do you think this is good practice or too much overhead? What about performance?

+7
delphi try-finally
source share
8 answers

In my opinion, there is only one reason why you should not <<< โ†’ << โ†’ or "in", as Mason pointed out ) a try / finally .

  • If the lifetime of objects is controlled by another object.

This management can take three forms:

  • A reference to an object has a scope outside the local block and is freed up in another place - as a field element freed in the destructor.
  • An object immediately added to the list, which is responsible for freeing the object later.
  • An object with an associated lifecycle manager, for example, how to transfer ownership to a VCL control during construction.

C # 1 , when a link has a wider scope, the link should immediately be set to zero unless it is built immediately. That way, when it is checked for reference, you know that you have an accurate reading. This is most common with member objects that are created as part of a larger class and then cleared when the parent object is destroyed.

C # 2 , when an object is added to the list, you want to use the try-except block (one of several times when I use it) only if an exception occurs after the object is built and before it is added to the control list. Ideally, the first line after building adds it to the list, or the list is actually a factory class that gives you an object already added to the list.

C # 3 , when an object has another lifetime manager, you really need to make sure that managing this manager is the right thing. If you create a VCL control, you may be tempted to have your own form (or any other control), but this actually imposes additional construction and destruction overheads. If this is possible, you should explicitly release it, this is especially true if you install the control once, then you know that you release it in your form destructor or when it closes. The only time you cannot do this is to make the control more dynamic.

So, it is best to use a lot of try / finally blocks. You should only have a few try / except blocks, and most of them should catch special types of exceptions and / or raise the exception again. If you have more try / except than try / finally blocks, then you are doing it wrong .

+15
source share

This is definitely the best example of using try-finally.

If an exception occurs, this object will be freed.

As for performance: measure before optimization.

+17
source share

As Frank said, "in terms of performance: measure before you optimize." Repeating this to emphasize.

In addition, if you create a bunch of objects in a method, you do not need to use a try..finally block for each of them. This can lead to ugly indentation. create, try, create, try, create, try, do something, finally, free, finally, free, finally, free. Wow Instead, you can set the object references to zero at the top of the method, then create them all, make one try block and free them all in the finally section.

This will save some overhead and performance (although you probably will never notice the difference), but more importantly, it will make your code cleaner and easier to read while maintaining the same level of security.

+13
source share

To answer the second part of your question:
try finally hardly any overhead.

In fact, there are many methods that have an implicit try ... finally block. For example, simply having a function using the local var of any type of interface and assigning a value.

- Jeroen

+5
source share

Last year, the other day, Delphi developers, I saw some of the secret codes of Marco Cantu, and he calls the attempt, finally, every time he creates something.

Someone asked him about this, and he said that he was trying to do this all the time.

But this is a particularly good idea for multi-threaded code when it comes to entering and exiting critical sections, although this is off topic, it's good to remember.

Obviously, sometimes it's a little intrusive, and if it's not in the culture of your work environment, to be in place in your shyness, it can make you look like plush shoes. But I think this is a good idea. This is similar to Delphi trying to force manual garbage collection.

+5
source share

If you create an object in the constructor of the class, and the object will belong to the surrounding class, you will want to free it in the destructor of the owner class.

I prefer to use FreeAndNil () instead of calling Free.

EDIT: But as others have said, you definitely always want to free what you create.

+2
source share

Yes, it is always a good idea (substantial) if the code that creates the object is responsible for releasing it. If not, then try / finally does not fit, but at the same time it is not. Anyway!

However, it can be cumbersome for this template code to fill your โ€œbusiness logicโ€, and you can consider an approach that has the same guarantee of freeing your objects, but which is much cleaner (and has other advantages), for example, my own implementation of AutoFree () .

Using AutoFree (), your code can be written as follows:

 aObject := TObject.Create; AutoFree(@aObject); aObject.AProcedure(); 

or, alternatively, since the implementation uses a link to a link (to enable auto-NIL'ing as well as Free'ing), you can even pre-register your links that you want to be autostarted to keep such housekeeping declarations from your business logic and keep the real "meat" of your code as clean as possible (this is especially useful when potentially multiple objects should be Free'd):

 AutoFree(@aObject1); AutoFree(@aObject2); aObject1 := TObject.Create; aObject1.AProcedure(); // Later on aObject2 is (or may be) also created : 

Not shown in my initial publication - this is another addition to the support mechanism for registering multiple links in a single call to AutoFree (), but I'm sure you can figure out the changes needed to support this yourself if you want to be able to do this:

 AutoFree([@aObject1, @aObject2]); aObject1 := TObject.Create; aObject1.AProcedure(); // Later on aObject2 is (or may be) also created : 
+1
source share

Even if it is recommended , I will not always do it.

My rules for using or not using try / finally:

  • The possibility of collapse and burning of this facility.
  • The number of objects created. If I know that your object is rarely created (no more than 5-6 times during the life of the application), I can live with a memory leak of 20 KB - if it "dies" without being freed.
  • The amount of leaked memory in the event of an object failure.
  • Code complexity. Try / except that the code looks very ugly. If there is a 5 line procedure, I always use try / except.
  • Application file size. If your application should work for several days, I finally want to free ANY piece of memory, otherwise the leak will accumulate.

The only place where it is difficult to make a decision is when you need performance when creating an object thousands of times (for example, in a loop). In this case, I do not use try / except if the object performs simple tasks, and there is little chance of seeing it fail.

-4
source share

All Articles