I ran into a bug the other day that I've run into enough times in my career that I thought it was worth sharing.
One of the perils of C++ is that it does certain things behind your back, and if you don't understand what those things are, they can bite you. One way this manifests is that apparently meaning-preserving changes can have surprising consequences.
In this recent case, I inherited some code that I was cleaning up. One of the changes was to change this:
foo = factory.getSomeClass();
Simple enough, right? But after making this change, a later access to
SomeClass foo = factory.getSomeClass();
Can you guess why? Here's a hint:
SomeClass uses a reference-counted shared-data implementation, similar to
Here's what happened:
SomeClass had defined an assignment operator, but not a copy constructor. The old code used the former, and the new code used the latter. In the absence of a user-defined copy constructor, the compiler generates one that just does a
bitwisememberwise copy. As a result, the reference count is copied and not incremented, and so later it becomes 0 before it should, and the data is deleted. A subsequent access to that data produces the segfault.
The solution is simple: Define a correct copy constructor. My own policy is never to rely on the compiler-generated copy constructor and assignment operator. When I write a new class, if I think I don't need these, I immediately add method prototypes for them that are private and have no implementations. Then, if you ever invoke them (deliberately or not), the compile will fail, and you'll know that you have to implement them for real (or change the calling code).Comments (0)