Generated destructor debugging in Visual Studio
I need to add a disclaimer. I understand that this method of adding breakpoints is common for debuggers like WinDbg. The target audience here is for those that mainly use and feel comfortable with Visual Studio debugging.
Often times, when I start investigating a bug, I know that a good place to start is when a particular class is being destructed. Easy enough, place the breakpoint on your destructor. However, what happens if you haven't created a destructor? Easy enough, code one and rebuild. One final problem, what happens if this given class lives in another component? Let's look at a substantially worthless example that illustrates this point.
namespace ExtNS
{
class ClassWithDestructor
{
public:
~ClassWithDestructor() {}
};
class ComponentClass : ClassWithDestructor
{
public:
ComponentClass( int data ) : m_importantData( data ) {}
int GetImportantData() { return m_importantData; }
private:
int m_importantData;
};
}
void main()
{
ExtNS::ComponentClass* c = new ExtNS::ComponentClass( 10 );
delete c;
}
Imagine for a moment that this class resides in an external component and contains some important, vital data for our program. Furthermore, consider that we have a bug where we have an invalid ComponentClass* and we want to know where our pointer is being deleted. First, we do not have the source code for this external component. Second and more important, the component class does not have an explicit destructor but its parent may.
Enter a nice feature in Visual Studio. We know that if a destructor is not explicitly defined but a parent class does, the compiler will generate one for us. We proceed with this knowledge. Ensure that symbols are loaded for the given component's library or executable (an explanation of how to accomplish this is outside the scope of this post). In the breakpoint window, click on the new dropdown and select "Break at Function... " Mine maps to [Ctrl+d, n]. Now, we enter our generated destructor as the function: ExtNS::ComponentClass::~ComponentClass.
If the function is found, you will see it as valid in the breakpoints window. Attach the debugger to a running instance and run the scenario. The breakpoint will hit whenever our class is being destructed. Obviously, we will not have the source code to see the breakpoint, but we can use the callstack to trace where we have stopped.