Reputation: 77
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
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_ptr
s in objects deeper within the Interface
object, so on Interface
delete statement the cascading destructors cause all unique_ptr
s 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