Чтобы использовать указатель, он должен указывать на что-то действительное или же быть нулевым. Все остальное приводит к нежелательным результатам.
Показанный вами код имеет неопределенное поведение , так как вы обращаетесь к памяти для lr
вне ее области действия, после того как закончилось ее время жизни. Единственная причина, по которой ваш код кажется «работающим», заключается в том, что эта память еще не была перезаписана, когда вы разыменовываете указатель.
Чтобы решить эту проблему, вы должны переместить объявление lr
за пределы if
block:
LRESULT CALLBACK Window::HandleMsgSetup(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) noexcept
{
LRESULT* ret = nullptr;
LRESULT lr; // <-- MOVED HERE!
if (msg == WM_NCCREATE)
{
const CREATESTRUCTW* const pCreate = reinterpret_cast<CREATESTRUCTW*>(lParam);
Window* const pWnd = static_cast<Window*>(pCreate->lpCreateParams);
SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(pWnd));
SetWindowLongPtr(hWnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(&Window::HandleMsgThunk));
lr = pWnd->HandleMsg(hWnd, msg, wParam, lParam);
ret = &lr;
}
return ret == nullptr ? DefWindowProc(hWnd, msg, wParam, lParam) : *ret;
}
В качестве альтернативы вы можете использовать std::optional
(только C ++ 17 и более поздние версии) вместо необработанного указателя, что избавит вас от необходимости объявите для него отдельную переменную, которая будет ссылаться на:
#include <optional>
LRESULT CALLBACK Window::HandleMsgSetup(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) noexcept
{
std::optional<LRESULT> ret;
if (msg == WM_NCCREATE)
{
const CREATESTRUCTW* const pCreate = reinterpret_cast<CREATESTRUCTW*>(lParam);
Window* const pWnd = static_cast<Window*>(pCreate->lpCreateParams);
SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(pWnd));
SetWindowLongPtr(hWnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(&Window::HandleMsgThunk));
ret = pWnd->HandleMsg(hWnd, msg, wParam, lParam);
}
return !ret.has_value() ? DefWindowProc(hWnd, msg, wParam, lParam) : ret.value();
}
Однако самое простое решение состоит в том, чтобы просто полностью исключить переменные LRESULT
, так как они вам на самом деле не нужны:
LRESULT CALLBACK Window::HandleMsgSetup(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) noexcept
{
if (msg == WM_NCCREATE)
{
const CREATESTRUCTW* const pCreate = reinterpret_cast<CREATESTRUCTW*>(lParam);
Window* const pWnd = static_cast<Window*>(pCreate->lpCreateParams);
SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(pWnd));
SetWindowLongPtr(hWnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(&Window::HandleMsgThunk));
return pWnd->HandleMsg(hWnd, msg, wParam, lParam);
}
return DefWindowProc(hWnd, msg, wParam, lParam);
}