Jump to content

dummzeuch

Members
  • Content Count

    2637
  • Joined

  • Last visited

  • Days Won

    91

Everything posted by dummzeuch

  1. Given a class like this: type TMyClass = class private FSomeInstance: TSomeOtherClass; public constructor Create(_SomeInstance: TSomeOtherClass); destructor Destroy; override; end; [...] constructor TMyClass.Create(_SomeInstance: TSomeOtherClass); begin inherited Create; FSomeInstance := _SomeInstance; // other code here end; destructor TMyClass.Destroy; begin FSomeInstance.Free; inherited; end; Note: The class takes ownership of the TSomeOtherClass instance passed to it in the constructor. It frees it in its destructor. How would you write the code constructing it? My current code looks like this: SomeInstance := TSomeOtherClass.Create; try MyInstance := TMyClass.Create(SomeInstance); SomeInstance := nil; finally FreeAndNil(SomeInstance) end; The try..finally is there for handling the case where TMyClass.Create raises an exception, so there won't be a memory leak. But unfortunately the destructor is called even for partially created instances, so if the code after assigning FSomeInstance raises an exception, the instance of TSomeOtherClass would be freed twice. The only safe way I can think of would be to change TMyClass.Create as follows: constructor TMyClass.Create(var _SomeInstance: TSomeOtherClass); begin inherited Create; FSomeInstance := _SomeInstance; _SomeInstance := nil; // other code here end; If an exception gets raised in the inherited constructor (or in any other code before setting FSomeInstance) FSomeInstance would be nil, and _SomeInstance would be freed in the calling code. If it happens after setting _SomeInstance to nil, the destructor would free FSomeInstance and the calling code would not, becuse the var parameter was set to nil, which FreeAndNil (or even .Free) would detect. Of course, I could use Interfaces and rely on reference counting.
  2. I was assuming that this constructor should replace the one in my original example, where it was called from within a try finally block: constructor TMyClass.Create(_SomeInstance: TSomeOtherClass); begin inherited Create; // other code here FSomeInstance := _SomeInstance; end; If that's not the case, you have a memory leak if the inherited Create fails.
  3. dummzeuch

    TTimer equivalent with smaller interval

    The TTimer component has a minimum interval of 50ms. I understand that this is a limitation of the Windows timer which uses messages. What would be the alternative if I need smaller intervals, e.g. down to 10ms? The code is still supposed to be run in the main VCL thread. It doesn't matter if some events get lost because executing the code takes longer than the timer interval because the computer is busy. I just want to be able to get a smaller interval if the computer can support it.
  4. As Dalija said: Raising exceptions in the constructor is possible and even normal (e.g. TFileStream.Create for a file that does not exist or maybe is only temporarily not available). It's documented that the destructor must handle partly constructed objects. Allen Bauer blogged about this in 2006 (aparently he has removed his About Me page from the blog, or did it never have one?) But yes, many Delphi developers are not aware of this. I only recently (as in "a few years, maybe a decade ago") became aware of this issue and am still finding code that does not take this into account.
  5. That Wikipedia article links to an article by Thomas Wang Prime Double Hash Table from 1997 which explains what the point of choosing a prime number is. That sounds plausible to me, unless of course it is outdated by now due to different implementations of hash tables and hash functions.
  6. dummzeuch

    TTimer equivalent with smaller interval

    (Plus some kind of time interval checking.) No, but it's an interesting idea. Unfortunately not helpful in my particular case as I have now determined that it is not the timer interval but the code executed in the event that causes my slow down effect. I have tried to optimize it but so far failed. There are too many complex dependencies on multithreaded code to easily find the culprit.
  7. Oh, TDictionary is hash table based. I wasn't aware of that. In that case, of course it should be much faster for significantly large lists.
  8. You mean like this? SomeInstance := TSomeOtherClass.Create; try MyInstance := TMyClass.Create(SomeInstance); except FreeAndNil(SomeInstance) raise; end;
  9. I don't see how assigning the field as the last operation in the constructor would solve the problem of duplicate destruction. Yes, if there is an exception, the class' destructor won't free SomeInstance and leave that for the finally block. But what if there is no exception? Then the try..finally around the construction will free SomeInstance and leave a stale pointer to an invalid instance inside the class.
  10. What kind of difference do you mean here? Performance or readability?
  11. There are very rare cases where Destroy won't be called, but I would simply ignore them in this context. Hm, assigning FSomeInstance before calling inherited Create. I am so used to call inherited Create as the first thing in the constructor, I didn't think of this. Sounds promising. Of course that only works if the destructor itself works as expected with a partially created object which - looking at the real world code this is about - I think doubtful. But that's a different problem I'll have to fix anyway.
  12. How would DI (I guess you mean dependency injection) solve this problem? Can you please give an example?
  13. How can you be sure? As always: Nobody has found and reported a bug (yet).
  14. dummzeuch

    TTimer equivalent with smaller interval

    Some interesting implementations, thanks. Not sure that I can use any of them though.
  15. It all depends on the definition of "good code". Of course my code is good code. 😉 The advantage of code without comments is that you don't have to worry about the comments being wrong or outdated because the code was changed (fixed) and nobody bothered with the comments because the code compiles anyway. And of course there are those absolutely unnecessary comments like: // for all 50 entries for i := 1 to 50 do begin // process the entry process(entry[i]); end; // we are done processing all entries But some programmers (and managers) still insist that these kinds of comments are necessary and a sign of a well documented code base. I definitely disagree here. But I think we degress.
  16. I certainly am not a Delphi expert in the sense that I don't make mistakes and always produce perfect code. (And as I just yesterday noticed (again) some of my "knowledge" about Delphi is outdated or even has been wrong in the first place). So, I don't really qualify for answering this question even though I have been working with Delphi for nearly my whole professional life. But here goes anyway: I'm never done improving or fixing even my own code base. And don't get me started on the code base of the company I work for. We still have code that is at least 15 years old and has never been refactored even though it is in dire need for that. It's improving slowly but I doubt that it will ever be up to even my standards.
  17. dummzeuch

    TTimer equivalent with smaller interval

    Yes, I just found that too and was suprised. Apparently my "knowledge" about this minimum interval goes back to Windows 95 times. This also matches the logs that I am currently looking at: The next timer event starts in the same millisecond that the last one ended. So apparently it's not the interval that's the limiting factor here but the code executed in the event. Thanks everybody. That's the answer.
  18. dummzeuch

    Tool to fix up uses clause unit namespaces?

    GExperts has this functionality, but only for the current unit. Feel free to use that code to build a batch tool (it's not quite so easy since you must take the project settings and search paths into account). I'll accept patches, of course. 😉
  19. dummzeuch

    Sort the Component Palette??

    You are aware that the component palette supports incremental search/filtering? Just checking...
  20. Unfortunately it's not always that simple: Assume a sub-procedure (since numbers is not a field): procedure GetItem(_idx: integer): integer; begin Result := numbers[_Idx]; end; Then call it with an invalid index. Range checking would detect it. Of course you could add code that checks for it: if (_Idx < Low(Numbers)) or (_Idx > High(Numbers) then raise EProgramerTooBloedError.Create('The programmer is an idiot!'); but then we are back to having to write code that could be autogenerated.
  21. I recently found that my image processing code became about 30% faster after turning off range checking. So I added a conditional define that allows me to turn it off for some units even of it is on in the project settings. But as stated above: In debug builds I usually turn it on and that has saved my a** several times.
  22. dummzeuch

    How to disable automatic adding of units to interface-uses

    No, there is no such option. You could add a unit alias for it, that redirects to a unit that's already there, e.g. SysUtils. Then the unit would still be added to the uses list, but would not be compiled into the executable.
  23. dummzeuch

    Filter Checkboxes for the Messages list?

    (Actually it's a Virtual String Tree, not a grid) Yes, I did, for various things. Unfortunately nothing much ever came from that, they didn't even fix the OTA bug that partly broke the Replace Component expert. And I can't waste any of my employer's support tickets on GExperts.
  24. dummzeuch

    Filter Checkboxes for the Messages list?

    Unfortunately there seems to be no way to access the text in the messages window in Delphi > 7. They switched from a list view (?) to a virtual string grid when they rewrote parts of the IDE. (If somebody knows a solution for this, I'd be happy to add quite a few new features to GExperts, that become possible with that.)
  25. dummzeuch

    Memory Management with many objects

    If switching to 64 bits is not feasible, you could try to enable IMAGE_FILE_LARGE_ADDRESS_AWARE which might solve the issue for now. (no idea where this formatting comes from, apparently I can't turn it off)
×