2016-06-15 97 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

相關問題