Irma
Irma

Reputation: 77

delete triggers exception in "_CRTDECL operator delete" in delete_scalar.cpp

I am writing a WinAPI application in C++.

Situation

I initialize Interface class in wWinMain and store the pointer to it into GWLP_USERDATA like so:

WinMain(...)
{
    ...

    //  INITIALIZE CUSTOM INTERFACE
    Interface* p_inface{new Interface(hWnd)}; // Create class object
    SetWindowLongPtrW(hWnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(p_inface)); // to retrieve it in callback

    ...
}

I initialize it like this because the Interface class initializes subclassed controls which require HWND to already exist, and I prefer my classes to fully initialize automatically in constructor.

In my WndProc callback I want to delete it like so:

WndProc(...)
{
    ...

    case WM_NCDESTROY:
    {
        Interface* p_inface{reinterpret_cast<Interface*>(GetWindowLongPtrW(hWnd, GWLP_USERDATA))};
        delete p_inface;
    }
    break;

    ...
}

Interface class header:

class Interface
{
    public:

    Interface(HWND const hWndParam);
    ~Interface();

    private:

    std::shared_ptr<Time> const p_time; // object holding timeframe information
    std::unique_ptr<Calendar> const p_calendar; // object handling calendar interface
    std::unique_ptr<MainMinimize> const p_minimize; // minimize button
    std::unique_ptr<MainClose> const p_close; // close button

    Interface(const Interface&) = delete;
    Interface& operator=(const Interface&) = delete;
};

And class project file:

Interface::Interface
(
    HWND const hWndParam // handle to main window
)
    : p_time(std::make_shared<Time>())
    , p_calendar{std::make_unique<Calendar>(p_time, hWndParam)}
    , p_minimize{std::make_unique<MainMinimize>(hWndParam)}
    , p_close{std::make_unique<MainClose>(hWndParam)}
{
}

Interface::~Interface()
{
}

Problem

I am getting exception pointing here (in delete_scalar.cpp) when the application tries to delete the p_inface pointer in WM_NCDESTROY of WndProc:

_CRT_SECURITYCRITICAL_ATTRIBUTE
void __CRTDECL operator delete(void* const block) noexcept
{
    #ifdef _DEBUG
    _free_dbg(block, _UNKNOWN_BLOCK); // << EXCEPTION: APPLICATION TRIGGERED BREAKPOINT
    #else
    free(block);
    #endif
}

I can't figure out why. I tried removing const from internal objects (didn't do the trick) and also reseting internal Interface class objects in destructor (this too didn't solve the issue).

When debugging I found that the pointer in WndProc is correct, and all objects within it except for Time shared_ptr are already wiped. They are intact in WM_DESTROY message though.

When looking for solutions I mostly found it triggering for people deleting objects on stack or mixing new with delete[]. One person mentioned "Most likely, either the point is not pointing to a valid heap allocated object, the heap has already been deleted or some other code has corrupted the heap."

Question

Can you please help me understand what mistake am I making and how to fix it so that the exception no longer triggers?

Upvotes: 1

Views: 1753

Answers (1)

Irma
Irma

Reputation: 77

The problem isn't the actual Interface object (thanks molbdnilo!), but the order of processed information within one of the base classes.

All my control classes which subclass WinAPI controls are stored in unique_ptrs in objects deeper within the Interface object, so on Interface delete statement the cascading destructors cause all unique_ptrs down the road to automatically destruct their objects.

The problem was that when I was sneaking pointer of the class (subclassing the control) into it's callback function through dwRefData, I was also deleting it in WM_DESTROY message - but the object was long gone due to unique_ptr clean up which happened sooner than the DESTROY message could have reached the queue.

So the solution: don't try deleting objects which are already handled by smart pointers!

Upvotes: 1

Related Questions