| Register | FAQ | Calendar | Search | Today's Posts | Mark Forums Read |
|
#1
| |||
| |||
| Hello I would like to use exceptions in my program to spare me all the checkes for the return code from various functions each time I call them. And also to make bugs like Access Violation look like they are handled and not crash my app. The problem is exceptions handlers are at many stack frames (nested called functions) away from the raise point, and in case of an exception all the called functions would return without destroing and freeing class instances created. I think this would cause memory and resource leaks. Do I have to begin each of my functions and procedures with try ... finally to be able to work with exceptions in my program ? Do I need a nested try ... finally for every class instance I create to be sure it is destroyed ? Is there a way to have the destructors always called by the language, like when the constructor raises the exception ? I know, I am used with other environments, but I would like to know how things are in Delphi. Thank you, Timothy Madden |
|
#2
| |||
| |||
| "Timothy Madden" <terminatorul@gmail.com> wrote in message news:Lucy121811247464650x9c256ec@jupiter.eamobile. ad.ea.com... > > Do I have to begin each of my functions and procedures with try ... > finally to be able > to work with exceptions in my program ? Do I need a nested try ... finally > for every > class instance I create to be sure it is destroyed ? If there is a chance it can exit that procedure before otherwise reaching the code that frees these instances (whether by exception or by deliberate choice) then yes - that is exactly what try/finally is for. In general, the use of try/except should be rare, use of try/finally generous. > Is there a way to have the destructors always called by the language, like > when the > constructor raises the exception ? No. Not unless you want to get into defining every class as a descendant of TInterfacedObject so that it has interface reference counting, but then you must also create and use instances of the *interface*, not the class - IOW you will need to make more tedious changes throughout your code than it will be to add try/finally blocks. -- Wayne Niddery - TeamB (www.teamb.com) Winwright, Inc. (www.winwright.ca) |
|
#3
| |||
| |||
| > Do I have to begin each of my functions and procedures with try ... > finally to be able > to work with exceptions in my program ? Do I need a nested try ... > finally for every > class instance I create to be sure it is destroyed ? As an aside, there is an additional use for try-finally: while not DataSet.Eof do begin try <code> if condition then Continue; {Continue with next record} <code> <code> <code> finally DataSet.Next; {Make sure the next record is really selected} end; end; Regarding exceptions, it is difficult to perfectly manage exceptions without resulting in needing to bring the app down. try-finally with exceptions are most useful when you know that an outer scope is going to handle exceptions with try-except; then you know that there are some conditions where the app is not going to come down due to an exception, and so you must make sure that any locally allocated memory is freed before moving into the exception handler. But it is difficult to be rigourous about this in practice. |
|
#4
| |||
| |||
| > Do I have to begin each of my functions and procedures with try ... finally to be able > to work with exceptions in my program ? No. As a simple rule put all code that has to be run to clean up in a finally section. Like Screen.Cursor := crHourClass; try LengthyOperation; finally Screen.Cursor := crDefault; end; or MyObject := TMyObject.Create; try MyObject.DoSomething; finally MyObject.Free; end; In both examples the first line is not inside the try block, simply because there is nothing to clean up in case it fails (if the mouse cursor never changes to an hourglass there is no need to restore it later). Just in case you wonder what's going on after a constructor like TMyObject.Create was execute successfully, but before the object was assigned to the MyObject variable: Some operations don't have to be protected by try/finally, simply because no exception can be raised there. > Is there a way to have the destructors always called by the language, like when the > constructor raises the exception ? Whenever an exception is raised within a constructor the destructor is called automatically. Afterwards exception handling continues normally and except and finally-blocks are executed. That's why a constructor call should not be made within the try-block, otherwise you'd destroy the object twice. Before a constructor is executed all fields are initialized with 0 / nil, that's why constructors partially executed usually don't confuse the destructor (it simply doesn't clean up fields which haven't been initialized yet). > Do I need a nested try ... finally for every > class instance I create to be sure it is destroyed ? For every class instance used locally inside of a function, yes. If you create and destroy more than one object at once there is an alternative to having two nested try/finally blocks: MyObject1 := TMyObject.Create; try MyObject2 := TMyObject.Create; try MyObject1.DoSomethingWith(MyObject1); finally MyObject2.Free; end; finally MyObject1.Free; end; or MyObject1 := nil; MyObject2 := nil; try MyObject1 := TMyObject.Create; MyObject2 := TMyObject.Create; MyObject1.DoSomethingWith(MyObject1); finally MyObject2.Free; MyObject1.Free; end; The latter works, because in case if any constructor fails or if the code afterwards fail, each object variable is either nil or valid. And since Free works with nil objects (and simply does nothing) that's alright, the object is not destroyed twice. > I know, I am used with other environments, but I would like to know how things are in > Delphi. One final thing: Raising a new exception in an except-block is alright, but never raise a new exception in a finally block! And since destructors are frequently called within finally-blocks, never raise an exception in a destructor! Clean-up code should always work without exceptions. -- Jens Gruschel http://www.pegtop.net |
|
#5
| |||
| |||
| > Is there a way to have the destructors always called by the language, like when the > constructor raises the exception ? Sorry, I misread your question, but Wayne already answered it. -- Jens Gruschel http://www.pegtop.net |
|
#6
| |||
| |||
| "Timothy Madden" <terminatorul@gmail.com> wrote in message news:Lucy121811247464650x9c256ec@jupiter.eamobile. ad.ea.com... > The problem is exceptions handlers are at many stack frames (nested > called functions) away from the raise point, and in case of an exception > all the called functions would return without destroing and freeing class > instances created. > > I think this would cause memory and resource leaks. Yes, it would. > Do I have to begin each of my functions and procedures with try ... > finally > to be able to work with exceptions in my program ? Not strictly like that, no. Just protect the individual objects you are using along the way, ie: procedure Test; var obj: TSomeClass; begin do some things... ... obj := TSomeClass.Create; try use obj as needed... finally obj.Free; end; ... do some more things... end; > Do I need a nested try ... finally for every class instance I create > to be sure it is destroyed ? Yes. > Is there a way to have the destructors always called by the language, > like when the constructor raises the exception ? No. Gambit |
![]() |
| Thread Tools | |
| Display Modes | |
In an effort to better serve ads to our visitors, cookies are used on objectmix.com. For more information, check out our Privacy Policy.