C++ Mishap Sign
I put up a sign at work to keep track of how many days we’ve worked without a C++ mishap.
A C++ mishap is defined as spending at least half an hour stumped by a perplexing programming problem, often accompanied by an inexplicable compiler error message, only to eventually discover that there was a fundamental C++ language feature that you didn’t know about, but surprisingly had never run into before, even though you’d spent several years using the language on a regular basis.
We’ve only had to reset the counter once in the 75 work days I’ve had the sign up so far.
A programmer was throwing an instance of an exception class of his own design. The class contained a character pointer to a C-style string he malloc’d. The string was being freed by the class’s destructor. The class didn’t define a copy constructor, as is generally required for classes that contain pointers to memory that they take ownership of. The programmer figured that this was unnecessary, because he was never explicitly making copies of instances of the class in his own code. (Obviously, this wouldn’t be an issue for STL strings.)
When the exception was thrown, the underlying exception handling system happened to copy the exception object using the compiler-provided default copy constructor and then destroy the original, leaving the object’s copy with a copied pointer to freed memory. When the copy of the exception object was destroyed, it’d try to free up the same memory again, crashing the program. However, for some reason, the compiler would only choose to invoke the copy constructor if the exception class was defined with a virtual destructor, and otherwise, it wouldn’t, and the bug would not show up. Originally, the programmer thought that the virtual destructor was somehow the cause of the problem, but this was a red herring.
There some additional silliness like if we explicitly defined our own copy constructor that did the right thing (strdup’ing the memory pointed to by the character pointer), the compiler wouldn’t bother to generate the code that called the copy constructor in the first place, sidestepping the bug, without calling the code that we had written to fix it.
When he first encountered the problem and tried to debug it, the programmer was surprised that the destructor was being called twice (once for the original object, and again for the unexpected copy of the object), and thought that this was a compiler bug invoked by the presence of the virtual destructor.
Like many suspected compiler bugs, it turned out to be a C++ feature.