Can't use SDL2 variables in Block scope

2019-09-05 15:18发布

问题:

I'm programming with SDL2, but I cannot grasp the reason behind the following. This works:

SDL_Window  *window;
SDL_Surface *screen_surface;
SDL_Surface *picture;

auto initWindow(void)
{…}
auto loadMedia(void)
{…}
auto close(void)
{…}

int main(void)
{
    initWindow();
    loadMedia();
    …
    close();
}

However this does not:

auto initWindow(SDL_Window *window, SDL_Surface *screen_surface)
{…}
auto loadMedia(SDL_Surface *picture, std::string resource)
{…}
auto close(SDL_Window *window, SDL_Surface *picture)
{…}

int main(void)
{
    SDL_Window  *window;
    SDL_Surface *screen_surface;
    SDL_Surface *picture;
    initWindow(window, screen_surface);
    loadMedia(picture, "resource_file.bmp");
    …
    close(window, picture);
}

The only difference is that I take window, screen_surface and picture out of file scope and put it into block scope (i.e. the main function), and instead of referencing global variables inside these functions, I use parameters. However when I try to run this, it displays a white screen, but doesn't display any errors. I don't understand what goes wrong here.

回答1:

Disclaimer : I have never done any SDL programming, so this is just an answer based on common sense and what I could read from the comments.

Say your initWindow function sets some value to the window variable. When that variable is declared in a global scope, modifications to it are also seen by all the other functions that use this variable.

This changes drastically when you change that variable to be a function parameter. Basing on the code you provided :

auto initWindow(SDL_Window *window, SDL_Surface *screen_surface)
{
    window = SDL_GetWindow(); /* or something */
}

int main(void)
{
    SDL_Window  *window;
    SDL_Surface *screen_surface;
    initWindow(window, screen_surface);
    /* some other code that uses 'window' */
}

Only the window in initWindow is actually set to the value of SDL_GetWindow. The window variable inside main is not changed : all the other functions that need to use it in main will be accessing an uninitialized variable, which is undefined behaviour. You also have a resource leak, since you're now never able to free what you got from SDL_GetWindow. initWindow actually receives a copy of window, a one that's totally unrelated to the window in main.

Seeing how you're using C++, the best way around this is to have initWindow accept a reference to the window variable, like this :

auto initWindow(SDL_Window *&window, SDL_Surface *&screen_surface)
{
    window = SDL_GetWindow(); /* or something */
}

int main(void)
{
    SDL_Window  *window;
    SDL_Surface *screen_surface;
    initWindow(window, screen_surface);
    /* some other code that uses 'window' */
}

Now, the window variable inside main will be updated with what initWindow does with it, and later code that uses window in main will access the resource that was acquired via SDL_GetWindow.

However, C++ allows you to manage resources in a more efficient way via the usage of constructors and destructors, a concept known as RAII (Resource Acquisition Is Initialization). Look for C++ wrappers around the SDL objects which will make your life much easier, and if you don't, spend a while to write your own, or make them work with std::unique_ptr (or std::shared_ptr if you know that you need it). You'll thank yourself for it later on.



标签: c++ sdl sdl-2