Ilia
Ilia

Reputation: 491

Why C++ try/catch does not catch the "pure virtual call" exception?

The following function is compiled in Microsoft Visual Studio 2017. In this function, CAttributedObject is a COM class implementing the IObjectID interface. The function must process notification about an event. Parameter pCaller is a pointer to an object of type CAttributedObject, which was the source of the event. The notification is dispatched to the main thread through its message queue. It is expected that by the moment the notification arrives, the object pointed by pCaller can be destroyed; this is why try/catch blocks are present in the code.

Sometimes, however, the call to QueryInterface raises a "pure virtual call" exception, which is not caught and causes the application to crash. There are many other cases where we test access to potentially deleted memory with try/catch, and the all has worked for years. I do not understand why "pure virtual call" exception is special.

HRESULT CDataProvider::OnObjIconChanged(
            BSTR Key, BSTR Path, IUnknown* pCaller,
            UINT Flags, __int64 hIcon, const CLSID& ProviderCLSID)
{
    CAttributedObject* pAttrObj = 0;
    IObjectID* pObjID = 0;
    try {
        try { pCaller->QueryInterface(__uuidof(IObjectID), (void**)&pObjID); }
        catch(...) {}

        if (pObjID != 0)
            pAttrObj = static_cast<CAttributedObject*>(pObjID);

        if (pAttrObj != 0)
        {
            pAttrObj->SetIcon((HICON)hIcon, Flags & SHGFI_SMALLICON);
            pAttrObj->Release();
        }
    } catch(...) {}

    TreeService()->Fire_ObjIconChanged(Key, Path, hIcon);
    return S_OK;
}

Upvotes: 1

Views: 972

Answers (1)

Sam Varshavchik
Sam Varshavchik

Reputation: 118445

I do not understand why "pure virtual call" exception is special.

Because it is undefined behavior, according to the C++ standard. Undefined behavior that indicates a bug in your code, somewhere. Given that this is undefined behavior, a C++ implementation may throw a catchable exception, but it is not obligated to do so. Most C++ implementations log a terse message, and abort() the entire program.

The only time a pure virtual function call could possibly be made within the bounds of the C++ standard is from a constructor or destructor of the abstract base class, and the C++ standard explicitly states this to be undefined behavior:

[class.abstract]

Member functions can be called from a constructor (or destructor) of an abstract class; the effect of making a virtual call to a pure virtual function directly or indirectly for the object being created (or destroyed) from such a constructor (or destructor) is undefined.

There is no other possible way to make an pure virtual function call, since you cannot instantiate, directly, abstract classes (classes with pure virtual functions) in C++, this is further hashed out elsewhere in the same clause.

Therefore, no matter which way you turn, you end up with undefined behavior. You have a bug in your code, somewhere, that either results in a pure virtual function call from a constructor or destructor, or memory corruption. This must be addressed not by catching some exception, but by locating the bug and fixing it.

If it was required to throw a catchable exception in this situation, it wouldn't be undefined behavior, wouldn't it?

Exceptions are not undefined behavior. Their mechanical working parts are fully defined in the C++ standard.

Upvotes: 3

Related Questions