Initialize With Care
Pointers are funny things. They are one of the make or break concepts for beginners, and even years later, they can cause grief to experienced developers. I am no exception. Here is one such story:
I was faced with a class which I wanted to refactor. It can be simplified as follows:
In the interest of breaking up the responsibilities, I added a couple of interfaces.
The idea is that I can pass around smart pointers to these interfaces and begin to decouple portions of the code. For example, I can inject them into classes that need them:
However, I made a mistake. I blame it on years of using boost::intrustive_ptr instead of std::shared_ptr, but enough excuses. Let's see if you can spot it.
Do you see it? If so, give yourself 5 points. If not, maybe after seeing the output:
'second' going out of scope...
'first' going out of scope...
'root' going out of scope...
Both shared pointers (first & second) are created from the original raw pointer. Therefore, they do not share a reference count. So, second cleans up without waiting for first to go out of scope. first later tries to free the memory, but it has already been cleaned up (a "double free").
What was confusing here is this was not caught by an assertion from the standard library. It took a Valgrind run to realize there was an issue. If we take the consuming class (InnocentBystander) out of the picture, the assertion is indeed hit.
Once we know what went wrong, the fix isn't terribly difficult: