tag:blogger.com,1999:blog-2428374771421713311.post1003656311916649994..comments2024-03-10T12:04:17.661-07:00Comments on The Oracle at Delphi: Exceptional SafetyAnonymoushttp://www.blogger.com/profile/10119008505905401707noreply@blogger.comBlogger18125tag:blogger.com,1999:blog-2428374771421713311.post-91378256786130094772006-11-05T20:45:32.000-08:002006-11-05T20:45:32.000-08:00Allen,Feel free to use it...The key advantages are...Allen,<br><br><br>Feel free to use it...<br><br><br>The key advantages are:<br><br>a) the lock xchg makes sure that only a single of multiple threads concurrently calling the procedure for the same variable will actually go ahead and try freeing the object.<br><br>b) the direct jump into the destructor prevents the need to first call Free, which then checks again if self is nil and then calls the destructor, after which the return address on the stack would go back to Free and from there back to FreeAndNil. The stack is in the same state when calling nxFreeAndNil and when calling the destructor. The only thing expected on the stack is the return address. By jumping to the destructor instead of calling to the destructor the RET in the restructor will later return directly to the caller of nxFreeAndNil instead of returning there just to find another RET statement.Thorsten Englernoreply@blogger.comtag:blogger.com,1999:blog-2428374771421713311.post-85093554778725747842006-11-01T03:02:35.000-08:002006-11-01T03:02:35.000-08:00Not seeing a freeAndNil for yesterday, just Assign...Not seeing a freeAndNil for yesterday, just Assigned. Did I miss something?C Johnsonnoreply@blogger.comtag:blogger.com,1999:blog-2428374771421713311.post-86567600616029409882006-11-01T22:33:06.000-08:002006-11-01T22:33:06.000-08:00Great ! ;-) I really appreciate this kind of posts...Great ! ;-) <br><br>I really appreciate this kind of posts - stories as they teach me how to do it better with my code... Keep on writting. :-)Lluis (Albert Research)noreply@blogger.comtag:blogger.com,1999:blog-2428374771421713311.post-26264715620860162672006-11-01T22:33:45.000-08:002006-11-01T22:33:45.000-08:00Allen, Just to be sure I got you, are you saying t...Allen, <br><br><br>Just to be sure I got you, are you saying that in the code:<br><br><br>var o: TMyClass;<br><br>if Assigned(o) then o.Free;<br><br><br>it makes NO sense to test for Assigned, and that one can safely simply call "o.Free" without testing for nil?<br><br><br>p.s.<br><br>I read this from your last sentance "Using the pattern, if FField <> nil then FField.Free; is a redundant, as is, if Assigned(FField) then FField.Free;"<br><br><br><br><br><br>Zarko Gajichttp://delphi.about.comnoreply@blogger.comtag:blogger.com,1999:blog-2428374771421713311.post-2074492583054984822006-11-01T23:52:47.000-08:002006-11-01T23:52:47.000-08:00Allen,please go on with these articles.I can get e...Allen,<br><br><br>please go on with these articles.<br><br>I can get enough of this insider stuff! ;-)<br><br><br>Reed Barnnoreply@blogger.comtag:blogger.com,1999:blog-2428374771421713311.post-77996451310790305592006-11-02T00:33:00.000-08:002006-11-02T00:33:00.000-08:00Ken, I wanted to warn about something else here .....Ken, I wanted to warn about something else here ... <br><br><br>Calling o.Free after o := nil is very bad as it will not call the destructor.<br><br><br>And also, calling o.Free without instantiating o to nil would produce some strange effects.<br><br>Zarko Gajicnoreply@blogger.comtag:blogger.com,1999:blog-2428374771421713311.post-24698287483326277242006-11-02T02:42:34.000-08:002006-11-02T02:42:34.000-08:00Allen, I was not talking about the destructor, but...Allen, <br><br><br>I was not talking about the destructor, but rather the following case<br><br><br>var obj : TMyClass;<br><br>begin<br><br> <br><br> {<br><br> a lot of code here BUT<br><br> maybe NOT a line like <br><br><br> obj:=TMyClass.Create<br><br> }<br><br><br> obj.Free //AV<br><br><br> *OR*<br><br><br> if Assigned(obj) then obj.Free //AV<br><br>end;<br><br><br>Therefore, obj must be assigned a NIL "value" if you are unsure whether something like obj := TMyClass.Create will be executed. Since local (inside a method) variables are NOT initialized to NIL as glogal (unit) or private (form level, for example) are.<br><br>Zarko Gajichttp://delphi.about.comnoreply@blogger.comtag:blogger.com,1999:blog-2428374771421713311.post-9048289436925865182006-11-02T04:53:22.000-08:002006-11-02T04:53:22.000-08:00Randy, That was the point. For an object instanc...Randy,<br><br><br> That was the point. For an object instance, you can be sure that all fields will be nil upon entering the constructor. Since they are guaranteed nil, you can safely only call Obj.Free; in the destructor even if that object instance was never allocated. The field will remain nil. However, if that field is "cycled" throughout the life of the object, then you *should* set it to nil whenever the instance is freed.<br><br><br>Allen.Allen Bauerhttp://blogs.codegear.com/abauernoreply@blogger.comtag:blogger.com,1999:blog-2428374771421713311.post-10958577046350524672006-11-01T03:19:38.000-08:002006-11-01T03:19:38.000-08:00I want more of these stories!How about writing a b...I want more of these stories!<br><br><br>How about writing a book with all the tidbits? It could be a "sequel" to Danny's book. It looks like Julian Bucknall's book printed through Lulu was a success.Patricio Moschcovichnoreply@blogger.comtag:blogger.com,1999:blog-2428374771421713311.post-81494239140464294502006-11-01T05:52:53.000-08:002006-11-01T05:52:53.000-08:00Thanks Allen, what an elightening post! Keep '...Thanks Allen, what an elightening post! Keep 'em coming!Sebastian Modersohnnoreply@blogger.comtag:blogger.com,1999:blog-2428374771421713311.post-43044200788918512302006-11-01T21:46:15.000-08:002006-11-01T21:46:15.000-08:00Oh by the way, while we're at it:What about th...Oh by the way, while we're at it:<br><br><br>What about the EmptyStr constant vs. '' ?Oliver Giesennoreply@blogger.comtag:blogger.com,1999:blog-2428374771421713311.post-51040624962490055722006-11-01T21:48:26.000-08:002006-11-01T21:48:26.000-08:00Ah, forget I ever said anything. I just found the ...Ah, forget I ever said anything. I just found the source comment in the SysUtils unit... ;)<br><br>D'Oh!Oliver Giesennoreply@blogger.comtag:blogger.com,1999:blog-2428374771421713311.post-70109234775578371532006-11-01T23:05:35.000-08:002006-11-01T23:05:35.000-08:00Zarko,Yes, you've got it. There is no point in...Zarko,<br><br><br>Yes, you've got it. There is no point in "if Assigned(o) then o.Free;", or<br><br>"if o <> nil then o.Free;". Just "o.Free" works fine. :-)Ken Whitenoreply@blogger.comtag:blogger.com,1999:blog-2428374771421713311.post-72875133257015771242006-11-02T00:40:39.000-08:002006-11-02T00:40:39.000-08:00Zarko, I think what Ken was getting at was that i...Zarko,<br><br><br> I think what Ken was getting at was that in the case of an instance of a class, the initialization of the all the instance fields are initialized to 0 automatically and *before* the constructor is run. Global variables are *also* initialized to 0 as well. I've seen this many times (and have been just as guilty of myself):<br><br><br>var<br><br> O: TObject = nil;<br><br><br>The nil assignment is not needed and in fact can serve to actually *increase* the size of your executable since it changes which segment that variable goes into in the EXE.<br><br><br>In *most* cases within a destructor, you need not set an instance field to nil after it has been freed because that memory is going to be deallocated anyway. Only in the rare cases where you have a set of classes that interact with one another that you *may* need to use FreeAndNil.Allen Bauerhttp://blogs.codegear.com/abauernoreply@blogger.comtag:blogger.com,1999:blog-2428374771421713311.post-46470701340050473502006-11-02T03:04:59.000-08:002006-11-02T03:04:59.000-08:00Zarko, In that case you should use the following ...Zarko,<br><br><br> In that case you should use the following pattern:<br><br><br>var<br><br> Obj: TMyClass;<br><br>begin<br><br> Obj := TMyClass.Create;<br><br> try<br><br> finally<br><br> Obj.Free;<br><br> end;<br><br>end;<br><br><br>If an exception is raised in the constructor, the "Obj :=" assignment will not occur, and since you've not entered the try..finally block, the Obj.Free; line will not execute either. In fact, in the above case, the exception should continue on to an outer scope and nothing else in this function will execute.<br><br><br>Allen.Allen Bauerhttp://blogs.codegear.com/abauernoreply@blogger.comtag:blogger.com,1999:blog-2428374771421713311.post-36486610917143316662006-11-02T04:44:00.000-08:002006-11-02T04:44:00.000-08:00Allen,My only issue here is that not all fields do...Allen,<br><br><br>My only issue here is that not all fields do get created. Sometimes they just don't. They were born nil and they die nil. But if you're making sure you call field.Free in the destructor, you get an A/V if no one ever created it....at least that is what I believe happens ;).<br><br><br>Am I wrong here? That's why I'm always checking Assigned()...not so much for a double free, but for a 'did you get created at all during the lifetime of this object'?Randy Magrudernoreply@blogger.comtag:blogger.com,1999:blog-2428374771421713311.post-48133236323647479142006-11-03T14:52:39.000-08:002006-11-03T14:52:39.000-08:00One thing to be aware of with FreeAndNil is that i...One thing to be aware of with FreeAndNil is that it's not thread-safe. If you have 2 threads trying to free the same object it can happen that both read the variable, both set the variable to nil and then both enter the destructor of the object.<br><br><br>That's one of the reasons why I use this implementation instead:<br><br><br>procedure nxFreeAndNil(var Obj);<br><br>asm<br><br> xor ecx, ecx<br><br> lock xchg [eax], ecx<br><br> mov eax, ecx<br><br> test eax, eax<br><br> {$IFNDEF DCC6OrLater}<br><br> jnz TObject.Free<br><br> {$ELSE}<br><br> jz @@Exit<br><br> mov dl, 1<br><br> mov ecx, [eax]<br><br> jmp dword ptr [ecx + VMTOFFSET TObject.Destroy]<br><br> {$ENDIF}<br><br> @@Exit:<br><br>end;<br><br><br>Thorsten Englernoreply@blogger.comtag:blogger.com,1999:blog-2428374771421713311.post-40205612570360379232006-11-04T08:13:54.000-08:002006-11-04T08:13:54.000-08:00Thorsten, Of course you're right, but I haven...Thorsten,<br><br><br> Of course you're right, but I haven't even gotten to the notion of thread-safety. However your implementation looks interesting... and maybe something we'll look into using ;-)<br><br><br>Allen.Allen Bauerhttp://blogs.codegear.com/abauernoreply@blogger.com