SDL为什么要在堆上创建纹理而不是堆栈

时间:2016-06-15 01:53:21

标签: c++ pointers memory heap sdl

所以我一直在阅读lazyfoos SDL2教程,我很好奇为什么在堆上创建所有SDL_Surface / SDL_textures等?我意识到SDL本身是用C语言编写的,函数接受/返回指针,但是为什么不在堆栈上创建表面并将它的引用传递给函数呢? (或在分配时取消引用)

希望我已经清楚了。这是一个代码片段,可以进一步尝试解释:

为什么:

void pointer()
{
    SDL_Surface *windowsurface;
    SDL_Surface *surface = SDL_LoadBMP("asdf.bmp");
    SDL_BlitSurface(surface, 0, windowsurface, 0);
}

而不是:

void stack()
{
    SDL_Surface windowsurface;
    SDL_Surface surface = *(SDL_LoadBMP("asdf.bmp"));
    SDL_Blit(&surface, 0, &windowsurface, 0);
}

如果后者确实可行,你还需要拨打SDL_FreeSurface吗?如果是这样,这将确保您不会泄漏任何记忆,因此我不会完全看到前者的好处。

希望这一切都有道理,我在SDL方面仍然是新手

3 个答案:

答案 0 :(得分:4)

这有很多原因,但我只关注一个。具体来说,在C ++中,没有可移植的方法来在堆栈的编译时创建大小未知的对象。

这是一个重大问题,因为纹理对于编译器来说是未知的大小,因为它不知道加载到它中的数据有多大。在C中,这对于使用VLA可能有所帮助,但由于许多操作系统上的堆栈大小很小,因此对于大型对象仍然不建议使用。

除了所有这些之外,纹理可以在GPU存储器而不是主存储器中实现。这绝对不能在堆栈上,并且必须由正在使用的任何系统中的图形例程来管理。这些图形系统通常只提供指向GPU内存中纹理的不透明指针,可以使用提供的例程释放或管理。

现在你可以争辩说句柄结构至少可以存在于堆栈中但实际上这提供了最小的节省,因为绝大多数读取和写入将是纹理本身而不是句柄对象所以优化它几乎没有值。

答案 1 :(得分:1)

这种方法存在一些问题:

$myClass->first()->callSecond();

首先,当函数退出时,对象void stack() { SDL_Surface windowsurface; SDL_Surface surface = *(SDL_LoadBMP("asdf.bmp")); SDL_Blit(&surface, 0, &windowsurface, 0); } windowsurface将被销毁,因为它们创建的堆栈部分将被回收用于调用函数。

其次,当它们被销毁时,它将通过调用等效的surface来完成,这可能不是那些对象的正确删除者。该库提供了自己需要调用的删除函数。

最后,位图对象的delete的赋值可能会很慢,因为位图可能很大。分配指针的速度要快得多。

管理从免费存储(堆)分配的对象的安全方法是使用智能指针

surface

std::unique_ptr中查找std::shared_ptrThe Manual

答案 2 :(得分:0)

我也更喜欢在没有必要时避免使用指针,但是许多游戏程序员在不需要时使用指针,使用new分配几乎任何大的指针,使其成为全局(!),并在最后调用delete。

使用动态分配有一个小优势(超过指针错误,IMJ的风险抵消)。在两个对象之间分配时,需要一个复制ctor,这意味着您必须决定是否共享内存。这通常是一个坏主意,如果你不这样做,你的副本可能需要做很多工作(而复制指针非常便宜)。更高版本的C ++消除了一些问题,但不是全部。

但是在SDL中,你真的被SDL选择不仅仅使用删除或免费解除分配,而是使用其特殊功能SDL_FreeSurfaceSDL_DestroyTexture等。对于使用此类功能的结构,您只是卡住了。因此,SDL程序员动态分配这些东西,即使他们不是硬核游戏程序员,他们认为视线中的所有东西都应该成为指针。你可以编写包装来清理一些东西,但在下面,你仍然坚持他们的删除程序。