2016-08-02 20 views
0

Also habe ich ein Memorey-Leck in meinem SDL2.0-Programm Ich schaffte es zu diesem Stück Code, Ich weiß nicht, ob ich nur blind bin, aber könnte jemand sehen, ob sie kann ein Speicherleck hier drin sein?SDL 2.0 Speicherleck

Ich danke jedem, der antwortet.

SDL_Color colour = { 255,255,255 }; 

SDL_Surface* surfaceMessage = nullptr; 

SDL_Texture* Message = nullptr; 

for (int i = 0; i < m_vItems.size(); i++) 
{ 
    if (surfaceMessage != nullptr) 
    { 
     SDL_FreeSurface(surfaceMessage); 
    } 

    SDL_Color colour = {255,255,255}; 
    if (i == m_iSelection) 
    { 
     colour = { 255,0,0 }; 
    } 

    surfaceMessage = TTF_RenderText_Solid(m_Font, m_vItems[i].c_str(), colour); // as TTF_RenderText_Solid could only be used on SDL_Surface then you have to create the surface first 

    Message = SDL_CreateTextureFromSurface(renderer, surfaceMessage); //now you can convert it into a texture 


    //Get split change 
    float thing = screenHeight - 2 * (screenHeight* 0.3); 
    thing /= m_vItems.size(); 

    SDL_Rect Message_rect; //create a rect 
    Message_rect.x = m_iPosX; //controls the rect's x coordinate 
    Message_rect.y = m_iPosY + (i * thing); // controls the rect's y coordinte 
    Message_rect.w = 0.18* screenWidth; // controls the width of the rect 
    Message_rect.h = 0.08 * screenHeight; // controls the height of the rect 

    SDL_RenderCopy(renderer, Message, NULL, &Message_rect); //you put the renderer's name first, the Message, the crop size(you can ignore this if you don't want to dabble with cropping), and the rect which is the size and coordinate of your texture 
} 

if (surfaceMessage != nullptr) 
{ 
    SDL_FreeSurface(surfaceMessage); 
} 
+0

Muss 'Message' den Speicher freigeben? – NathanOliver

+3

@NathanOliver-Texturen brauchen tatsächlich ihren Speicher frei, obwohl die Funktion * technisch * ['SDL_DestroyTexture'] benannt ist (https://wiki.libsdl.org/SDL_DestroyTexture). OP wäre vielleicht am besten mit 'std :: unique_ptr' aber – jaggedSpire

+0

@jaggedSpire Cool. Ich habe nie SDL verwendet, also war es nur eine Vermutung, da es ein Zeiger war und die Oberfläche gereinigt wurde. – NathanOliver

Antwort

3

Texturen müssen mit der SDL_DestroyTexture Funktion zerstört werden, und Sie tun nicht das, was auf dem Speicherverlust führt.

übrigens manuell die Zerstörung Funktion auf einem Rohzeiger aufrufen, wenn Sie nicht mehr benötigen fehleranfällig ist (man leicht einen Fall vergessen kann, wo es gehen muss) und unnötig, mit der wunderbaren Welt der Ressourcen Acquisition Ist Initialisierung (RAII).

Sicherstellen, dass die erworbenen Ressourcen ordnungsgemäß entsorgt werden, ist in C++ eigentlich eine ziemlich häufige Anforderung, und eine, für die es gut geeignet ist. Sie können die Objektlebensdauer zum Verwalten von Ressourcen für Sie mithilfe von RAII abrufen, bei der Sie Destruktor/Deallokationscode im Destruktor der Klasse platzieren, sodass dieser automatisch ausgeführt wird, wenn das Objekt, das die Ressource verwaltet, den Gültigkeitsbereich verlässt. Dies macht die Ausnahmesicherheit ebenfalls einfach, da der Destruktorcode auch im Falle einer Ausnahme ausgeführt wird.

In Ihrem Fall haben Sie einen Klassenspeicher einen Zeiger auf das erstellte SDL-Objekt, und rufen Sie dann die entsprechende SDL Ende der Lebensdauer Funktion für die Vielzahl der Objekte im Destruktor verwaltet, also a Textur-Management-Klasse könnte wie folgt aussehen:

class Texture{ 
SDL_Texture* texture_; 
public: 
    // or simply pass the arguments for texture creation in and create it internally 
    Texture(SDL_Texture* texture) : texture_{texture}{} 
    ~Texture(){ 
     if (texture_ != nullptr){ 
      SDL_DestroyTexture(texture_); 
     } 
    } 

    // ... functions to access texture 
}; 

Beachten Sie aber, dass Sie im wesentlichen einen Zeiger auf eine Ressource mit atypischen End-of-Lebensdauer Anforderungen Verpackung und dass diese Anforderungen sind im wesentlichen eine freie Funktion aufzurufen, die nimmt den Zeiger als Argument, vorausgesetzt, es ist kein Nullzeiger.

Sie brauchen nicht eine bestimmte Klasse zu machen dass-- unique_ptr war entworfen für diesen Job zu tun und wird es vortrefflich tun, wenn Sie es eine benutzerdefinierte deleter geben. Einen benutzerdefinierten Deleter zu geben ist eine einfache Aufgabe, auch unique_ptr.

Wenn Sie eine Funktion haben, die einen Zeigertyp T* als einziges Argument nimmt und beendet die Lebensdauer des spitzen Gegenstand und einen zugehörigen Speicher, es ist so einfach wie diese:

#include <memory> 

void shoutFooDestruction(Foo* foo); // my special lifetime ending function 

int main(){ 
    std::unique_ptr<Foo, decltype(&shoutFooDestruction)> ptr{ 
     new Foo(), 
     shoutFooDestruction};  
    ptr.reset(new Foo()); 
} 

Dies ruft shoutFooDestruction zweimal: einmal für den ursprünglichen Zeiger, der dem eindeutigen Zeiger zu Beginn seiner Lebensdauer gegeben wurde, und aufgerufen, wenn reset war, und einmal für den Foo, der beim Zurücksetzen geliefert wurde, wenn die Lebensdauer des unique_pointer am Ende von main endet.

See it live on Coliru

Das Äquivalent für eine SDL_Texture wäre:

std::unique_ptr<SDL_Texture, &SDL_DestroyTexture> message{ 
    nullptr, 
    SDL_DestroyTexture}; 

und für eine SDL_Surface:

std::unique_ptr<SDL_Surface, &SDL_FreeSurface> surfaceMessage{ 
    nullptr, 
    SDL_FreeSurface}; 

würden Sie dann reset auf die einzigartigen Zeiger aufrufen, wenn Sie wollte eine neue Textur oder Oberfläche von SDL, und sie würden jede alte Textur oder Oberfläche entsorgen e für dich. Alle verbleibenden Inhalte der unique_ptr s am Ende der Funktion würden mit den gleichen Funktionen behandelt werden, wenn die unique_ptr s außerhalb des Geltungsbereichs ging.


1. Wie in 3 Konstrukteurs gesehen und 4

2. reset Aufruf auf einem einzigartigen Zeiger mit nullptr für ihr Wert will not call the provided deleter und das gleiche gilt für unique_ptr's destructor, so dass Sie nicht Sie müssen sich darum sorgen, den Löschanruf zu vermeiden, wenn Sie nichts zu löschen haben.

+0

Ich habe eine ausführlichere Beschreibung über die Verwendung von RAII auf C-style-Schnittstellen hier: [Verwenden von RAII zum Verwalten von Ressourcen aus einer C-style API] (http://stackoverflow.com/questions/39176805/using-raii -verwalten-Ressourcen-von-ac-style-api) – jaggedSpire