Note: Most of this page is about pointer management in CeePlusPlus.
[From
ClassicOoAntiPatterns. See also
ClassesWithoutOo.]
You have
CeePlusPlus as your first
ObjectOrientedLanguage. You get so sick of trying to handle object references without
GarbageCollection that you end up making many classes into Singletons. Then you discover that singletons, being not-very-cleverly-disguised globals, make the code hard to refactor. Later you discover
ReferenceCounting ("smart") pointers and spend a week building and testing a
SmartPointer template [this being pre-STL]. You think you're home free, but then you get caught by circular references. Finally, you find a language that has real GC and stuff C++ away in a closet. --
WayneConrad
The
StandardTemplateLibrary has no
ReferenceCounting or list-based
SmartPointer.
AutoPtr is merely an ownership passing pointer. It's only good for locals to do automatic cleanup and to protect you from exceptions. If you use an auto_ptr as a member variable, you're asking for pain.
Note that making every module a singleton reduces the modularization to
CeeLanguage-style file modules, which certainly was workable beforehand, if not the best practice. What did you forget since then?
Besides, why aren't you using the constructor and destructor properly?
CeePlusPlus doesn't need magic
GarbageCollector threads to do its dirty work. You know exactly at what point objects will be destroyed and you can easily clean up. Resource leaks aren't as common as non-C++ people assume they are.
Ohhhh yes they are. My own experience is that *every* commercial project whose primary language is C or C++, as it tends toward its (desired) release date, is entirely dominated by finding and fixing memory management bugs. Eventually, the team sets a threshold of pain, and will ship knowing that memory management bugs exist, but are hit "rarely enough". -- ArlieDavis
Moreover, even so-called
GarbageCollected languages have
ResourceLeaks, if not memory leaks. Any operation that needs to be balanced will fail. So, no magic bullet there. Indeed, with
CeePlusPlus using the constructor/destructor to balance actions automatically is a common idiom and one that I sorely miss in
JavaLanguage.
And let's not forget that
GarbageCollectors lure you into a false sense of security where you may fail to clear references to objects, or let references hang while a thread is busy. This causes memory leaks. Indeed, if you lose control of references in a non-garbage-collected language, you only leak one node, whereas in a
GarbageCollected language, you lose the entire subgraph rooted at that node.
GarbageCollectors only permit you to lose track of the nodes; you still have to keep track of the edges. There's an article on this in
DrDobbsJournal Feb2000, if you're interested. --
SunirShah
Actually, STL doesn't have an
auto_ptr class either. The
AutoPtr class (a
SmartPointer with
exclusive-owner semantics) is part of the
CeePlusPlus "Standard Library" - which is very different from Stepanov's "
StandardTemplateLibrary". Of course, much,
but not all of STL was added to the existing
CeePlusPlus "Standard Library". For what it's worth, at one time the "Standard Library" was considering a template class named
counted_ptr. This had a similar interface to
auto_ptr but used "shared-owner" instead of "exclusive-owner" semantics. Since it was not added, most programmers have rolled their own
counted_ptr that looks (but does not act) like
auto_ptr. --
RobertDiFalco [See also
CppCountedPointerImplementation]
I thought there was a reference-counted pointer in STL - I jumped to
JavaLanguage before STL became big; that's my excuse for not knowing. Thanks for setting me straight.
What I'm really talking about here is spending over half my time at the computer dealing with
CeePlusPlus pointers - making sure that things are freed in the destructor (and did I remember to make the destructor virtual), making sure that pointers are set to null or otherwise initialized in the constructor, making sure that the right thing is done with pointers when the object is assigned to, trying to figure out which of the 4 objects holding a pointer 'owns' the pointer and is therefore responsible for freeing its memory, spending late nights at the terminal trying to figure out which of the above I screwed up, causing an abend at some point far, far away from where the actual programming error was made. Sunir, it's not that I couldn't do it right - I got pretty good at it - it's that I started to resent how much time it was taking to do it right, time that should have been spent solving the
customer's problems, not the
language's problems. --
WayneConrad
All languages have trade-offs. There is a lot in
CeePlusPlus that is clearly easier to do than in the
JavaLanguage and vice versa. A good example is that unpredictable monstrosity called
finalize for releasing resources or the inability to make an instance of an immutable class, constant by modifier. There are no universal truths in software development, each tool has its place--and it's here that Sunir and Wayne go off course trying to pit one against the other, as if they aren't apples and oranges. One cannot discount a
GarbageCollected language any more than a non-garbage collected language, any more than I type safe, dynamically-bound, or statically-bound language. And, for what it's worth, there are many packages that provide
GarbageCollection to
CeePlusPlus. Of course, if you are doing all this to
CeePlusPlus, it probably isn't the appropriate language choice for the job--i.e. just use a higher-level language.
However, I think if the subject is
ProducingSingletonGarbage, then the above example isn't a good one. I don't think I even agree with the moniker. Personally, I would do something more language-neutral and rename the OO
AntiPattern to something like
UsingSingletonToHideGlobalData where, in
any O-O language, one uses the
SingletonPattern as a global lexical scope instead of a way to enforce a single instance of some class. As you know, there are many pages here on Wiki that criticize this use of the
SingletonPattern to dress up the use of Globals. --
RobertDiFalco
By the way, I seem to have gotten away from my original point and into an anti-CeePlusPlus rant. I was saying that overuse of SingletonPattern was a mistake I fell into, and if we can confirm that others have fallen into that same mistake, then it can qualify as one of the ClassicOoAntiPatterns. --
WayneConrad
In the
LispLanguage world, the standard idiom to manage your resources is to have a macro, say WITH-SOME-RESOURCE, used thusly:
(with-some-resource (resource parameters)
(execute-some-body))
and the macro ensures that the resource is released when execution leaves its body (via an UNWIND-PROTECT). We do this with locks, databases, file-handles, etc. Simple, elegant, and correct. I thought I'd miss
CeePlusPlus's destructors, but I was
way wrong. --
AlainPicard
On the subject of finalizers and managing resources that the
GarbageCollection doesn't know about, see also
ResourceAcquisitionIsInitialization,
DeterministicResourceManagement, and
ReleasingResourcesInJava. UNWIND-PROTECT is more or less try/finally with no catch - but without macros it remains tedious to do it properly.
RubyLanguage uses the "with-some-resource" idiom with blocks. In Ruby, a resource class provides a class-method that takes a block. This method allocates a resource object, passes the object to the block, and then releases the object after control has returned from the block. Classes often overload their instantiator methods to return a new object if called without a block, or to use the "with-some-resource" idiom if called with a block. E.g.
# Allocate and return a file object:
file = File.open( "some_file.txt", "r" )
# Allocate a file, pass it to the block, close the file after the block
File.open( "some_file.txt", "r" ) do |file|
process( file )
end
The semantics of ref-counted pointers can be complicated, which is why the standard library doesn't include one. There's one (more than one, actually) in the fabulous
BoostLibraries.
AndreiAlexandrescu's Loki library has some (very neat) ones too, see
ModernCeePlusPlusDesign.
DeeLanguage has the best of both worlds when it comes to resource management, imo, since it has both GC (which you can easily sidestep if you need to, like when you need to pass a pointer to a C library)
and automatic objects you can use for RAIA. D is very much like "A better C++ for the people who actually like C++" and I'd be happy if it managed to get some more mind share.
See also
SingletonPattern,
SingletonsAreEvil
CategoryGarbageCollection