C makes it easy to shoot yourself in the foot; C++ makes it harder, but when you do it blows your whole leg off.
I want to share with you a strange bug I’ve been struggling with last week.
from Bjarne Stroustrup's FAQ: Did you really say that?
I had an application that crashed whenever a user logged out and then logged back. I couldn’t understand why during the 2nd login attempt all hell broke loose – I got the finger equivalent of the C++ world - “corrupted memory” exception.
I had the best minds try and use their debugging powers to try and catch the cause of that memory issue thing but to no avail. That is until a simple breakpoint solved the mystery.
Due to NDA and time constraint let me simplify the problem- I had two classes:
The factory definition looks something like this:
- a Factory of sorts
- Some Object created by that factory
The “Object” class had many important methods that did interesting stuff to the benefit of the users – however for this example we only care about its constructor:
And that’s it – see the problem yet?
Obviously this cyclic reference (factory is passed to object that was created by factory) is asking for trouble but that’s not the problem (yet).
Let me show you how GetObject was implemented:
using namespace std;
Do you see the problem? If not - take a minute to think about it…
In case you’re not familiar with shared_ptr – it’s essentially a smart pointerwhich was introduced in C++ 11 (and before that in Boost):
Manages the storage of a pointer, providing a limited garbage-collection facility, possibly sharing that management with other objects.
The problem is that a misguided soul (read: yours truly) has used it the wrong way.
shared_ptr works by reference counting – each new assignment increase that count and every time the object goes out of scope the count is decreased.
The fix was simple – I’ve changed the c’tor to receive MyFactory as a plain-old-honest-to-god reference.
- When I’ve created a new shared_ptr instance from this it was created with count of one.
- All was good and well until after MyObject constructor ended in which point the count was decreased.
- Since no other shared_ptr objects were holding the pointer – MyFactory desructor was called
- An exception – not right away (we’re talking C++ here) but most of the time the next time you try and do something with MyFactory
The lesson learnt
shared_ptr is a great thing – it’s one the useful new gadgets that made it into the new C++ 11.
I’m using it all the time – it help me write simple, elegant C++ code, But like everything else in the C++ world – make sure you understand what you’re doing.
Labels: C++, C++ 11