Утечка памяти Обнаружение и переопределение нового? - PullRequest
5 голосов
/ 15 июля 2009

Я пытаюсь настроить обнаружение утечек памяти с помощью этих двух статей: http://msdn.microsoft.com/en-us/library/e5ewb1h3%28VS.80%29.aspx http://support.microsoft.com/kb/q140858/

Итак, в моем stdafx.h у меня теперь есть:

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

#define new new(_NORMAL_BLOCK,__FILE__,__LINE__)

Единственная проблема в том, что у меня есть класс, который переопределяет новую функцию:

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

Теперь, когда я компилирую этот код, я получаю: ошибка C2059: синтаксическая ошибка: «константа» ошибка C2091: функция возвращает функцию

Есть идеи, как я могу это исправить?

Ответы [ 4 ]

10 голосов
/ 15 июля 2009

Вы можете использовать прагматические директивы для сохранения и восстановления нового макроса, если он не найден при перегрузках. См. [MSDN] (http://msdn.microsoft.com/en-us/library/hsttss76(VS.71).aspx) для точного синтаксиса.

* 1005 Е.Г. *

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

Вы можете поместить их в заголовки, например,

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

А потом

#include "begin_new_override.h"
void FAR* operator new(size_t cb);
#include "end_new_override.h"
4 голосов
/ 15 июля 2009

Переопределение new через #define на уровне препроцессора - плохая идея по моему опыту - вы не только преодолеваете operator new перегрузки, но также размещаете new и, возможно, несколько других вещей.

Распространение всех этих макросов FILE и LINE во все стороны приводит к тому, что ваши секции .rodata и .data переполняются строками файлов и номерами строк, и генерирует гораздо больше кода за вызов.

Гораздо лучше (если приложить больше усилий заранее) использовать преимущества отладочной информации (например, файла .pdb) и использовать что-то вроде библиотеки *1011* StackWalk64 для сбора информации о стеке.

Перегрузить различные комбинации глобальных операторов new и delete оператора (массив, nothrow и т. Д.), Заставить их сохранять и освобождать информацию стека по мере выделения и освобождения памяти.

Вы даже можете хранить эту информацию в структуре, такой как std :: map , просто будьте осторожны, чтобы не записывать выделения, вызванные вставками карты (глобальной блокировки может быть достаточно для однопоточного приложение, многопоточное оставлено в качестве упражнения для читателя).

Поскольку вы записываете весь стек для любого заданного выделения, вы можете выполнить изящный анализ дерева, сгруппировав распределения (утечки или иные) по «функциям и потомкам» ... И иногда легче отследить сложные утечки, если Вы знаете весь стек по времени их выделения.

4 голосов
/ 15 июля 2009

Вместо того, чтобы определять new как нечто иное, почему бы не перегрузить оператор new?

Добавьте эти определения функций где-нибудь в глобальном пространстве имен:

// 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();

Затем вы можете определить свой собственный новый макрос, который обращается к неглобальным версиям, и реализовывать глобальные версии, чтобы утверждать или предупреждать, если они вызваны (чтобы поймать что-нибудь проскальзывание).

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

Ваши перегрузки на уровне класса будут работать, как и ожидалось, если вы вызовете 'new' прямо в классе. Если вы хотите вызвать MY_NEW для класса, вы можете, но вам придется переопределить перегрузку в классе, чтобы она соответствовала вашему новому.

1 голос
/ 15 июля 2009

Try #undef new до определения класса а затем #define new new... снова после.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...