Arguing with a Decade-Old Eric Lippert Post
But it’s on the first page of Google results for c++ smart pointer addref release so I have to do this, dammit!
The post in question is: Smart Pointers are Too Smart.
Does this code look correct?
map[srpFoo.Disown()] = srpBar.Disown();
It sure looks correct, doesn’t it?
Nope, it looks like a disaster waiting to happen. The map ought to have keys and values that are smart pointers, so the correct code would be:
map[srpFoo] = srpBar;
If the map holds raw pointers, that in itself is the error, because it will necessitate some complicated dance to transfer ownership in and out, which means bandying around raw pointers casually, and in C++ that leads to disaster, because it can only be done safely in code paths that can be proven to not throw exceptions.
In fact its even more general and simple than that. If you write some code in your C++ program that initiates any state at all, and the previous state will not be restored automatically during stack unwinding, and you haven’t taken the time to prove that no exceptions will be thrown during this state, you’re doing it wrong.
Far from showing what goes wrong when you use smart pointers, Eric showed what goes wrong when you stop using them, even for a nanosecond. If you never use them, the wrongitude will be uninterrupted.
It’s quite possible that forcing yourself to put all the
Release calls in the right places by hand will have a sort of positive side-effect: you will be so distracted by this effort that you will not have sufficient time or patience to be productive, and so this will force you to write only very simple programs, which is definitely a good thing, but perhaps arrived at for the wrong reasons.
And conversely, when a problem becomes rarer, it seems more egregious. “I remember the good old days, in the Blitz, when we were being bombed every day, but at least we were used to it!”
The real problem underlying all of COM is probably that
IUnknown doesn’t provide a way to attach a listener for when the object is destroyed. If it had this, we could create a safe “weak” pointer, one that doesn’t keep the object in existence but is automatically set to
nullptr when the object expires. This is addressed in the more recent WinRT variety of COM, where all sensible objects should implement IWeakReferenceSource, and in fact classes created with C++/CX do this automatically.
And ultimately this is perhaps the simplest response to Eric’s blog post: with C++/CX, smart pointers are baked into the language. Reference count cycles will still occur, no question, which is why the whole exercise is a silly step backwards, but only relative to something much better: pick just about any managed GC-enabled runtime.