2016-08-04 61 views
-11
bool CPythonNonPlayer::LoadNonPlayerData(const char *c_szFileName) 
{ 
    DWORD dwElements; 

    TMobTable *pTable = (TMobTable *) zObj.GetBuffer(); 

    for(DWORD i = 0; i < dwElements; ++i, ++pTable) 
    { 
     TMobTable *pNonPlayerData = new TMobTable; 
     memcpy(pNonPlayerData, pTable, sizeof(TMobTable)); 
     m_NonPlayerDataMap.insert(TNonPlayerDataMap::value_type(pNonPlayerData->dwVnum, pNonPlayerData)); 
    } 

    return true; 
} 

Meine Frage ist: was mache ich falsch? Dies führt zu einer Menge Speicherverlust. Nach jedem Aufruf dieser Funktion erhöht sich die Anwendungsnutzung um 10 MB.Dynamische Zuweisung verliert Speicher?

+5

Jedes Mal, wenn Sie ein 'neues' haben, brauchen Sie ein' delete'. Ich sehe nicht, dass Sie 'delete' verwenden. – NathanOliver

+2

Versuchen Sie nicht, 'new' und' delete' zu ​​verwenden. Dies wird dich vor viel Ärger und Trauer bewahren. –

+2

Dieser Code wird Speicher verlieren, wenn "map :: insert" fehlschlägt. Schreiben Sie niemals Code wie diesen, wenn Sie eine "Map" verwenden, um einen Zeiger auf dynamischen Speicher in einer Karte zu speichern, und nehmen Sie einfach an, dass die map.insert funktioniert. Wenn der Schlüsselwert in der Map bereits vorhanden ist, liegt ein Leck vor. – PaulMcKenzie

Antwort

3

Das Problem ist nicht in dieser Funktion. Das Problem liegt in der Art, wie Sie mit m_NonPlayerDataMap umgehen. Diese Funktion überträgt den Besitz einiger Objekte auf diese Karte, und die Verantwortung für diese Karte liegt bei delete, wenn sie damit erledigt ist. Ich wette, das tut es nicht.

Übrigens, um diese Art von Problem zu vermeiden tun Sie das einfach nicht. Verwenden Sie nicht new, es sei denn Sie müssen wirklich. Erstellen Sie stattdessen eine Karte der Werte statt einer Karte von Zeigern. Wenn Sie keine Möglichkeit finden, dies zu erreichen, sollten Sie zumindest intelligente Zeiger anstelle von rohen Zeigern verwenden.

+3

Es ist schlimmer als das. Wenn der Befehl map :: insert fehlschlägt, weil der Schlüssel bereits in der Map existiert, ist das Leck garantiert. – PaulMcKenzie

1

Verwenden Smart-Pointer-Wrapper Speicherverwaltung für Sie zu behandeln, zum Beispiel:

Bei Verwendung einer älteren Version als C++ 11:

#include <memory> 

// std::auto_ptr is not container-safe! 
typedef std::map<DWORD, TMobTable*> TNonPlayerDataMap; 
TNonPlayerDataMap m_NonPlayerDataMap; 

... 

bool CPythonNonPlayer::LoadNonPlayerData(const char *c_szFileName) 
{ 
    DWORD dwElements = ...; 
    ... 

    // I'm assuming this just returns a pointer to an existing memory 
    // buffer and is not actually allocating a new buffer. If it is, 
    // you need to free it when you are done copying it... 
    // 
    TMobTable *pTable = (TMobTable *) zObj.GetBuffer(); 

    for(DWORD i = 0; i < dwElements; ++i, ++pTable) 
    { 
     std::auto_ptr<TMobTable> pNonPlayerData(new TMobTable); 

     // don't use memcpy! better would be to give TMobTable a copy constructor instead... 
     // std::auto_ptr<TMobTable> pNonPlayerData(new TMobTable(*pTable)); 
     // 
     *pNonPlayerData = *pTable; 

     // if successful, release local ownership of the object. 
     // if failed, ownership will remain here and free the object when the auto_ptr goes out of scope. 
     // 
     if (m_NonPlayerDataMap.insert(std::make_pair(pNonPlayerData->dwVnum, pNonPlayerData.get())).second) 
      pNonPlayerData.release(); 
    } 

    return true; 
} 

Alternativ, wenn Sie mit C++ 11 oder später:

#include <memory> 

// std::unique_ptr is container-safe! 
typedef std::map<DWORD, std::unique_ptr<TMobTable>> TNonPlayerDataMap; 
TNonPlayerDataMap m_NonPlayerDataMap; 

... 

bool CPythonNonPlayer::LoadNonPlayerData(const char *c_szFileName) 
{ 
    DWORD dwElements = ...; 
    ... 

    // I'm assuming this just returns a pointer to an existing memory 
    // buffer and is not actually allocating a new buffer. If it is, 
    // you need to free it when you are done copying it... 
    // 
    TMobTable *pTable = (TMobTable *) zObj.GetBuffer(); 

    for(DWORD i = 0; i < dwElements; ++i, ++pTable) 
    { 
     std::unique_ptr<TMobTable> pNonPlayerData(new TMobTable); 
     // 
     // or, if using C++14 or later: 
     // std::unique_ptr<TMobTable> pNonPlayerData = std::make_unique<TMobTable>(); 

     // don't use memcpy! better would be to give TMobTable a copy constructor instead... 
     // std::unique_ptr<TMobTable> pNonPlayerData(new TMobTable(*pTable)); 
     // std::unique_ptr<TMobTable> pNonPlayerData = std::make_unique<TMobTable>(*pTable); 
     // 
     *pNonPlayerData = *pTable; 

     // if successful, ownership of the object is transferred into the map. 
     // if failed, ownership will remain here and free the object when the unique_ptr goes out of scope. 
     // 
     m_NonPlayerDataMap.insert(std::make_pair(pNonPlayerData->dwVnum, std::move(pNonPlayerData))); 
    } 

    return true; 
}