Well, DynamicArrays are referenced counted, exactly the same way as AnsiStrings / UnicodeStrings so really there's no way you could've missed free-ing it... ... or is there?
From experience, the first thing that came to mind was that since it's a referenced-counted container - and as with the rest, it's prone to circular-references.
Consider the following code:
#include <vcl.h>With the 'refs' member of DynamicArray<TCircularRef> base referring back to itself (base[0].refs = base), we ended up with a circular-ref. Yes, the cirular-ref in the above example is easy to spot and would probably never occur in the real world as well. In reality though, the circular-refs are much harder to spot and assignments change during run-time, depending on the code branch and/or timing. What's worse is that the reference could be held by an object of which you pass to another library written by someone else...
#pragma hdrstop
#include <iostream.h>
struct TCircularRef
{
DynamicArray<TCircularRef> refs;
~TCircularRef() { cout << "here" << endl; }
};
#pragma argsused
int main(int argc, char* argv[])
{
DynamicArray<TCircularRef> base;
base.set_length(1);
base[0].refs = base;
base.set_length(0);
return 0;
}
Notice that the above sample code tries to break the circular-ref such that it would get cleaned-up with the line base.set_length(0)? Alas, that was to no avail as its ref-count prior to set_length would be 2, which leaves us with a ref-count of 1 after that. Can we call set_length(0) again then? No. Why? Because 'base' no longer knows about the object it once held as the first set_length(0) would've set it to point to the new memory location allocated by set_length(0).
Is there a way out? There're a few. But none to my liking. (You could Google for 'circular-reference' if you're interested to find a solution to this but it's not the intention of this article).
As I have a garbage collector library ready to be used in any projects I create with C++ Builder, that was the solution I took. I simply replaced all DynamicArray with gc_array and allocated it with gcnew_array. With that, I no longer had to care about the hairy problem of who owns the object, who's responsible to free it and whether there's a potential circular reference problem in my code. What's more, it's thread-safe, unlike DynamicArray. But that's a topic for another day.
In short, this is my advice: Avoid DynamicArray at all costs!
2 comments:
@Bijayani
This post has nothing to do with VC++. And C++ Builder has CodeGuard built-in.
Your comment shows you have *not* read the article and was simply trying to promote your link.
I've therefore deleted your post. I will report abuse to Google should you try that again.
Post a Comment