2009-07-14 10 views
5

Sto tentando di ottenere il rilevamento di perdite di memoria di lavoro con l'aiuto di questi due articoli: http://msdn.microsoft.com/en-us/library/e5ewb1h3%28VS.80%29.aspx http://support.microsoft.com/kb/q140858/Perdita di memoria Rilevamento e annullamento di una nuova?

Così nel mio stdafx.h mi hanno ora:

#define _CRTDBG_MAP_ALLOC 
#include <stdlib.h> 
#include <crtdbg.h> 

#define new new(_NORMAL_BLOCK,__FILE__,__LINE__) 

L'unico problema è, io avere una classe che sostituisce la nuova funzione:

class Dummy 
{  
    //overloaded new operator 
    void FAR* operator new(size_t cb); 
} 

Ora, quando compilo questo codice, ottengo: errore C2 059: errore di sintassi: errore 'costante' C2091: funzione restituisce funzione

Qualche idea su come posso risolvere questo problema?

+0

Questo è il problema con le macro :( – GManNickG

+0

Se non si sta utilizzando Windows, suggerirei valgrind. – LiraNuna

+0

userei DUMA se fossi usando Windows. – EFraim

risposta

9

È possibile utilizzare le direttive pragma per salvare e ripristinare la nuova macro in caso di sovraccarico. Vedere [MSDN] (http://msdn.microsoft.com/en-us/library/hsttss76(VS.71).aspx) per la sintassi esatta

Eg

#pragma push_macro("new") 
#undef new 
void FAR* operator new(size_t cb); 
#pragma pop_macro("new") 

È possibile inserire questi nelle intestazioni, ad esempio

begin_new_override.h:.

#ifdef new 
#define NEW_WAS_DEFINED 
#pragma push_macro("new") 
#undef new 
#endif 

end_new_override.h:

#ifdef NEW_WAS_DEFINED 
#undef NEW_WAS_DEFINED 
#pragma pop_macro("new") 
#endif 
.210

E poi

#include "begin_new_override.h" 
void FAR* operator new(size_t cb); 
#include "end_new_override.h" 
+0

fresco, non avevo idea di questo è stato possibile :-) –

1

Prova #undef new prima definizione di classe e poi di nuovo dopo #define new new....

4

Invece di definire nuovi di essere qualcosa di diverso, perché non sovraccaricare operatore nuovo?

aggiungere queste definizioni di funzioni da qualche parte nel namespace globale:

// operator new overloads 
void* operator new(const size_t size, const char* file, int line) throw(); 
void* operator new(const size_t size, const size_t align, const char* file, int line) throw(); 
void* operator new[](const size_t size, const char* file, int line) throw(); 
void* operator new[](const size_t size, const size_t align, const char* file, int line) throw(); 

// can't easily overload operator delete 
void operator delete(void* ptr) throw(); 
void operator delete[](void* ptr) throw(); 

// matched to the operator new overload above in case of exceptions thrown during allocation 
void operator delete(void* ptr, const char* file, int line) throw(); 
void operator delete[](void* ptr, const char* file, int line) throw(); 
void operator delete(void* ptr, const size_t align, const char* file, int line) throw(); 
void operator delete[](void* ptr, const size_t align, const char* file, int line) throw(); 

// global new/delete 
void* operator new(size_t size) throw(); 
void* operator new(size_t size, const std::nothrow_t&) throw(); 
void* operator new(size_t size, size_t align) throw(); 
void* operator new(size_t size, size_t align, const std::nothrow_t&) throw(); 

void* operator new[](size_t size) throw(); 
void* operator new[](size_t size, const std::nothrow_t&) throw(); 

void operator delete(void* ptr, const std::nothrow_t&) throw(); 
void operator delete[](void* ptr, const std::nothrow_t&) throw(); 

Quindi è possibile definire il proprio nuova macro che chiama attraverso alle versioni non globali e implementare le versioni globali per far valere o mettere in guardia se' chiamato (per prendere qualsiasi cosa sfugga).

#define MY_NEW(s) new(s, __FILE__, __LINE__) 

vostri sovraccarichi a livello di classe funzionerà come previsto se si chiama 'nuova' direttamente sulla classe. Se si desidera chiamare MY_NEW sulla classe, è possibile ma sarà necessario ridefinire il sovraccarico della classe in modo che corrisponda al nuovo.

+1

'__LINE__' è un' int', non un 'char *'. – Cornstalks

+0

Mi ha aiutato a comprendere gli overload specifici per gli operatori new ed delete. – Vinzenz

4

Ridefinire new tramite #define a livello preprocessore è una cattiva idea nella mia esperienza - non solo rompere operator new sovraccarichi, ma anche il posizionamento new, e probabilmente un paio di altre cose.

Avendo tutte quelle macro FILE e LINE in espansione ovunque, le sezioni .rodata e .data si gonfiano con stringhe di file e numeri di riga e genera molto più codice per chiamata.

Molto meglio (se uno sforzo maggiore up-front) per sfruttare l'esistenza di informazioni di debug (ad esempio .pdb file) e usare qualcosa come la libreria del StackWalk64DbgHelp per raccogliere informazioni stack.

Sovraccarico delle varie combinazioni dell'operatore globale new e dell'operatore delete (array, nothrow, ecc.), Memorizzano e rilasciano le informazioni stack quando la memoria viene allocata e liberata.

È anche possibile memorizzare queste informazioni in una struttura come uno std :: map < void *, StackInfo >, basta stare attenti a non registrare i Allocati causati dagli inserti mappa (un blocco globale può essere sufficiente per un singolo app filettata, multi-threaded è lasciato come esercizio al lettore).

Poiché si sta registrando l'intero stack per ogni allocazione assegnata, è possibile eseguire un'adeguata analisi ad albero, raggruppando le allocazioni (perdite o altro) per "funzione e discendenti" ... ed è talvolta più facile rintracciare le perdite complicate se conosci l'intero stack dal loro tempo di allocazione.

+0

Per inciso, se qualcuno già sa di una libreria/toolkit per fare questo genere di cose (informazioni sull'assegnazione dei negozi con tracce dello stack) sotto Windows - salvo soluzioni commerciali - Mi piacerebbe sentirne parlare e aggiornerò felicemente la risposta . Nessun motivo per reinventare la ruota. La versione di questo ho usato era su una piattaforma embedded ... – leander

+1

Prova a cercare tracce ETW con Windows. Gli strumenti sono gratuiti e di piccole dimensioni, quindi possono essere rilasciati sulle macchine client per facilitare il debug. Inoltre puoi inserire informazioni extra nelle tracce etw dalla tua applicazione. possono tracciare allocazioni di memoria e deallocations e acquisire informazioni sullo stack per ognuno di essi. La cosa più difficile è che impostare WPA per mostrare le informazioni che vuoi può essere scoraggiante. Ci sono alcuni video utili collegati qui per iniziare: https://randomascii.wordpress.com/2014/08/19/etw-training-videos-available-now/ – 0xC0DEFACE