【问题标题】:Can't use SDL2 variables in Block scope不能在块范围内使用 SDL2 变量
【发布时间】:2016-05-21 13:57:44
【问题描述】:

我正在使用 SDL2 进行编程,但我无法理解以下原因。这有效:

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();
}

但事实并非如此:

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);
}

唯一的区别是我把windowscreen_surfacepicture文件范围中取出,放到块范围中(即主函数),而不是在这些函数中引用全局变量,我使用参数。 但是,当我尝试运行它时,它会显示一个白屏,但不会显示任何错误。我不明白这里出了什么问题。

【问题讨论】:

  • 使用您的 IDE 调试器单步执行这两个版本以查看区别的理想人选。
  • void f(int x) {x = 5;} int main() {int i = 7; f(i); printf("%d\n", i);} 打印什么,为什么?
  • 要详细说明initWindow(SDL_Window *window, SDL_Surface *screen_surface),您正在传递此声明中指针的副本
  • @henrikgiesel 没有? C 没有引用调用这样的东西。
  • @henrikgiesel:是的,在您调用 initWindow 函数之前,它们会指向内存中的同一个位置。但是,在initWindow 中,您更改 已复制 指针指向的内容。问题是这不会影响main 中声明的指针,您只是修改initWindow 中的复制 指针

标签: c++ sdl sdl-2


【解决方案1】:

免责声明:我从未做过任何 SDL 编程,所以这只是基于常识和我从 cmets 中可以读到的答案。

假设您的initWindow 函数为window 变量设置了一些值。当该变量在全局范围内声明时,使用该变量的所有其他函数也可以看到对它的修改。

当您将该变量更改为函数参数时,这会发生巨大变化。根据您提供的代码:

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' */
}

只有initWindow 中的window 实际上设置为SDL_GetWindow 的值。 main 中的 window 变量没有改变:所有其他需要在 main 中使用它的函数将访问一个未初始化的变量,这是未定义的行为。你也有资源泄漏,因为你现在永远无法释放你从SDL_GetWindow 得到的东西。 initWindow 实际上收到了window副本,与main 中的window 完全无关。

看看您是如何使用 C++ 的,最好的解决办法是让 initWindow 接受对 window 变量的引用,如下所示:

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' */
}

现在,main 中的 window 变量将更新为 initWindow 对其所做的操作,稍后在 main 中使用 window 的代码将访问通过 SDL_GetWindow 获取的资源。

但是,C++ 允许您通过使用构造函数和析构函数以更有效的方式管理资源,这一概念称为 RAII(资源获取即初始化)。寻找 SDL 对象周围的 C++ 包装器,这将使您的生活更轻松,如果您不这样做,请花一些时间编写您自己的,或者让它们与 std::unique_ptr(或 std::shared_ptr,如果您知道您需要它)。以后你会感谢自己的。

【讨论】:

  • 我会做的稍有不同的一件事是,我不会使用SDL_Window *&window 作为参数,而是使用SDL_Window **window。这迫使您在呼叫站点使用&window,一目了然地表明该值可能会发生变化。 (但这只是风格问题,其他人可能不同意。)
  • @Alex:当然。我认为拥有SDL_Window** 会太 C-ish。 ;)
  • 它有效,但我想知道,为什么会有这样的行为?我知道SDL_Window 是某种struct(SDL2 实际上是一个C 库)。当我自己声明一个struct 时,创建一个指向该结构的指针并将其传递给一个函数,就像我所做的那样,在这里,它按预期工作。
猜你喜欢
  • 1970-01-01
  • 2022-01-17
  • 1970-01-01
  • 2017-08-05
  • 1970-01-01
  • 2020-09-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多