2016-06-15 94 views
1

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

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

为什么:

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

+0

这很可能是因为SDL的对象具有SDL库必须跟踪的内部资源。这要求SDL对象的所有实例化和销毁都由库直接完成,只有库负责100%的对象生命周期管理;因此唯一可能的实现是基于堆的分配和销毁。 –

+0

所以我必须创建堆上的所有表面?我问的原因是因为我有很多类作为成员的纹理,并希望避免担心复制构造函数和我的所有类的分配。 – picklechips

+0

在第二个例子中,当函数退出时,'windowsurface'被销毁。我会想象大多数纹理需要超越它们创建的功能。 – Galik

回答

2

有一大堆的原因,但我会专注于一个。具体而言,在C++中,没有可移植的方式在编译时在堆栈上创建大小未知的对象。

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

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

现在您可以争辩说句柄结构可以存在于堆栈中,但实际上这提供了最小的节约,因为绝大多数读写操作都是针对纹理本身,而不是处理对象,因此优化了价值不大。

0

我也喜欢避免指针时没有必要的,但许多游戏程序员使用指针当不需要时,分配相当多的东西大与新的,使其全球(!),并在最后呼吁删除。

使用动态分配有一个小优点(多于指针错误的风险IMJ)。当你在两个对象之间分配时,你需要一个拷贝,这意味着你必须决定是否共享内存。这通常是一个坏主意,如果你不这样做,你的副本可能需要做很多工作(而复制指针非常便宜)。 C++的后续版本可以避免这个问题,但不是全部。

但是,在SDL中,您真的被SDL选择不是简单地使用删除或释放来释放,而是使用其特殊功能SDL_FreeSurfaceSDL_DestroyTexture等。对于使用此功能的结构,您只是被卡住了。因此SDL程序员动态地分配这些东西,即使他们不是那些认为看起来一切都应该成为指针的硬核游戏程序员。你可以编写包装来清理一些东西,但是在下面,你仍然停留在删除例程中。

1

有这种方法的几个问题:

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

首先,对象windowsurfacesurface会当函数退出被销毁,因为它们是建立在将被回收堆栈的一部分调用函数。

其次,当它们被销毁时,它将通过调用delete的等价物来完成,这可能不是这些对象的正确删除方法。该库提供了自己的需要调用的删除功能。

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

管理从自由存储区(堆)分配的对象以安全的方式是使用智能指针

// create a special deleter that calls the correct function 
// to delete the object 
struct SDL_Surface_deleter 
{ 
    void operator()(SDL_Surface* surface) const { SDL_FreeSurface(surface); } 
}; 

// some type aliases for convenience 
using SDL_Surface_uptr = std::unique_ptr<SDL_Surface, SDL_Surface_deleter>; 
using SDL_Surface_sptr = std::shared_ptr<SDL_Surface>; 

SDL_Surface_uptr make_unique_surface(SDL_Surface* surface) 
{ 
    return SDL_Surface_uptr{surface}; 
} 

SDL_Surface_sptr make_shared_surface(SDL_Surface* surface) 
{ 
    return {surface, SDL_Surface_deleter{}}; 
} 

void smart_objects() 
{ 
    // no need to delete this 
    auto unique_surface = make_unique_surface(SDL_LoadBMP("asdf.bmp")); 

    // no need to delete this either 
    auto shared_surface = make_shared_surface(SDL_LoadBMP("asdf.bmp")); 

    // stuff... 
} 

查找std::unique_ptrThe Manualstd::shared_ptr

+0

感谢您的回应!所以使用智能指针我能够避免创建复制构造函数/赋值?我想我需要更多地看看智能指针。 – picklechips

相关问题