Более простой метод для вставки значения в потенциально нулевой указатель - PullRequest
2 голосов
/ 01 апреля 2020

У меня есть указатель, который я sh должен указать на LRESULT, который я возвращаю из функции. В настоящее время для вставки значения, возвращаемого функцией, я сохраняю его во временной переменной, а затем указываю на эту переменную. Я хочу знать, есть ли способ сделать это без временной переменной.

Ниже приведен кодированный пример:

LRESULT* ret = nullptr;
//---
LRESULT temp = foo();
ret = &temp;
//---
return ret == nullptr ? bar() : *ret;

Я пытался использовать это:

*ret = foo();

Но это не работает, поскольку ret является нулевым указателем и не имеет выделенной памяти для ввода значения.

Я также пробовал это:

ret = &(foo());

Но это делает не работает так же.

edit:

для контекста полная функция, над которой я работаю, выглядит следующим образом:

LRESULT CALLBACK Window::HandleMsgSetup(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)  noexcept
{
    LRESULT* ret = nullptr;
    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));
        LRESULT lr = pWnd->HandleMsg(hWnd, msg, wParam, lParam);
        ret = &lr;
    }
    return ret == nullptr ? DefWindowProc(hWnd, msg, wParam, lParam) : *ret;
}

и еще раз повторю, функция работает штраф в его текущем состоянии, я просто wi sh, чтобы удалить, казалось бы, незаметную переменную lr

Ответы [ 2 ]

4 голосов
/ 01 апреля 2020

Я думаю, что вы можете сделать что-то подобное, тогда вы можете удалить обе переменные ret и lr .

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);
}
1 голос
/ 01 апреля 2020

Чтобы использовать указатель, он должен указывать на что-то действительное или же быть нулевым. Все остальное приводит к нежелательным результатам.

Показанный вами код имеет неопределенное поведение , так как вы обращаетесь к памяти для 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);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...