Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C4533 warning: why does goto skip variable initialization?

Tags:

c++

I'm getting:

warning C4533: initialization of 'b' is skipped by goto FreeDC.

But if the code gets to the label FreeDC in WM_CREATE, 'b' is not initialized. How its initialization could be skiped, if it is not initialized in that situation. I just don't understand the warning.

#include <windows.h>

class A
{
    int i;

    public:
    A() {};
    A(int i) : i(i) {}
};

LRESULT CALLBACK WndProc(HWND, UINT, UINT, LONG);

HINSTANCE ghInstance;

/************************************************************************************************************************

    WinMain(hInstance, hPrevInstance, pszCmdLine, nCmdShow)

************************************************************************************************************************/

int APIENTRY WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR pszCmdLine, int nCmdShow)
{
    ghInstance = hInstance;

    WNDCLASSEX  wndclassx;

    wndclassx.cbSize        = sizeof(WNDCLASSEX);
    wndclassx.style         = CS_HREDRAW | CS_VREDRAW;
    wndclassx.lpfnWndProc   = WndProc;
    wndclassx.cbClsExtra    = 0;
    wndclassx.cbWndExtra    = 0;
    wndclassx.hInstance     = hInstance;
    wndclassx.hIcon         = NULL;
    wndclassx.hCursor       = LoadCursor(NULL, IDC_ARROW);
    wndclassx.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
    wndclassx.lpszMenuName  = NULL;
    wndclassx.lpszClassName = L"WndProc";
    wndclassx.hIconSm       = NULL;

    if( !RegisterClassEx(&wndclassx) ) return 0;

    HWND hWnd = CreateWindow(L"WndProc", L"", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
                             CW_USEDEFAULT, NULL, NULL, hInstance, NULL);

    ShowWindow(hWnd, SW_SHOWMAXIMIZED);
    UpdateWindow(hWnd);

    MSG msg;

    while( GetMessage(&msg, NULL, 0, 0) )
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    //  Retorna msg.wParam

    return (int)msg.wParam;
}

/************************************************************************************************************************

    WndProc(hwnd, message, wParam, lParam)

************************************************************************************************************************/

LRESULT CALLBACK WndProc (HWND hwnd, UINT message, UINT wParam, LONG lParam)

{
    static A a;
    static int i;

    switch ( message )
    {
        case WM_CREATE:
        {
            HDC hDC;
            if( !(hDC = GetDC(hwnd)) ) return -1;

            int iLogPixelsY = GetDeviceCaps(hDC, LOGPIXELSY);

            LOGFONT lf;
            memset(&lf, 0, sizeof(LOGFONT));
            lf.lfHeight = -MulDiv(11, iLogPixelsY, 72);
            wcscpy_s(lf.lfFaceName, LF_FACESIZE, L"Cambria Math");

            HFONT hFont;
            if( !(hFont = CreateFontIndirect(&lf)) ) goto FreeDC;

            hFont = (HFONT)SelectObject(hDC, hFont);

            int j = 5;
            i = j;

            A b(2);
            a = b;
            return 0;

            FreeDC: ReleaseDC(hwnd, hDC);
            return -1; 
        }
        break;

        case WM_DESTROY:

        PostQuitMessage(0);
        break;

        default:

        return DefWindowProc(hwnd, message, wParam, lParam);
    }
    return 0;
}
like image 551
Ayrosa Avatar asked Mar 21 '26 14:03

Ayrosa


2 Answers

b's constructor won't called if you use goto, and yet it's still in scope. This is technically an error, although some compilers only give off a warning.

Here's an example:

int main() {
  goto foo;
  int bar = 5;
  foo:
  ++bar; // doesn't work if goto is used - bar isn't initialized
}

It may seem like you are not using b, but its destructor is still being called:

int main() {
  goto foo;
  A b;
  foo:
  b.~A(); // compiler silently adds destructor and other cleanup here
          // won't work if goto is used - b isn't initialized
}
like image 92
Pubby Avatar answered Mar 23 '26 06:03

Pubby


You could avoid the problem by introducing a suitable local scope that gets skipped by the goto:

        HFONT hFont;

        if( !(hFont = CreateFontIndirect(&lf)) )
        {
          goto FreeDC;
        }

        hFont = (HFONT)SelectObject(hDC, hFont);

        {               // new scope; skipped entirely by goto
          int j = 5;
          i = j;

          A b;
          a = b(2);
        }

        return 0;

    FreeDC:
        ReleaseDC(hwnd, hDC);
        return -1;

If you think about C++ and scopes and automatic object lifetimes really carefully, you'll come to conclude that goto really wreaks havoc with the entire programming model. That's why there are many (often quietly implied) conditions on where you can go-to and wher not. Generally, jumping into the middle of a scope is problematic if the scope contains new automatic variables. We avoid this by introducing a new, local scope that the goto jump skips entirely.

like image 44
Kerrek SB Avatar answered Mar 23 '26 06:03

Kerrek SB



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!