Прекратите звонить перегруженным новым и удалите оператора с помощью контейнеров stl - PullRequest
3 голосов
/ 09 февраля 2011

Я разрабатываю инструмент утечки памяти.В этом я перегружаю оператор new и delete.Работает нормально.Но код, для которого я создаю этот инструмент, составляет около 15000 строк.Я не могу изменить существующий код, только я могу вызвать функцию инструмента утечки памяти в существующий код.Существующий код, содержащий контейнеры stl (например, список, карта, стек и т. Д.).Контейнер Stl также вызывает операторы new и delete для выделения или освобождения памяти.я хочу, чтобы контейнер stl вызывал оператор new и delete, которые не являются перегруженными new и delete.Например:

int *iptr = new int[10] ----> should call overloaded new[]
delete [] iptr -------------> should call overloaded delete[]
map.insert(10) -------------> should call default new[] ( which are in new.h)
map.erase()  ---------------> should call default delete[] ( which are in new.h)

Как я могу это сделать?Любая помощь будет оценена.

Извините, я забыл упомянуть, что заменяю new и удаляю следующие макросы:

#define new DEBUG_NEW
#define DEBUG_NEW TrackMemory(__FILE__, __LINE__) ->* new
#define delete TrackDelete(__FILE__, __LINE__); delete

здесь TrackMemory используется для отслеживания памяти, а new используется длявыделить память так же, как удалить.Мой инструмент также работает нормально, но когда в изображение попадают контейнеры stl, он дает неверный результат, потому что они используют только перегруженные новые.пожалуйста, помогите мне

Ответы [ 3 ]

2 голосов
/ 09 февраля 2011

15000 строк?Ну, замените все вызовы new и delete вызовами методов-оберток в вашем коде (использование макросов для регистрации __FILE__ и __LINE__ может быть первым шагом), и все будет сделано быстро.

Или используйте существующий инструмент, например valgrind .

2 голосов
/ 09 февраля 2011

Начиная с написания этих «пустых» функций. Они заменят стандартные новые и удалят ваши самостоятельно:

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

Затем напишите отдельные функции для выделения и освобождения памяти:

void *myNew (size-t memorySize);
void myDelete (void *memoryPointer);

Позвоните myNew и myDelete в функции, упомянутые в начале.

Реализация myNew и myDelete с использованием HeapAlloc и HeapFree.

Затем создайте глобальную переменную и пометьте ее так (это Visual Studio):

#pragma init_seg(lib)

Это будет гарантировать, что ваша глобальная переменная инициализируется первой, а очищается последней.

Пока мы рассмотрели основы. Чтобы получить реальную функциональность отчетов об утечках, вам нужно будет хранить информацию о выделенной памяти в вашей функции myNew.

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

Кроме того, вы можете использовать StackWalk для получения стека вызовов, а также сохранять его при каждом выделении памяти.

Некоторые, вероятно, задаются вопросом, почему вы хотите сделать это вместо использования других инструментов:

  • По моему опыту, отчеты об утечках в Visual Studio ограничены. Он не показывает вам стек вызовов, а только прямой вызов, что делает его бессмысленным.
  • некоторые инструменты используют #define для замены new, delete, alloc, ..., но в некоторых случаях это может вызвать проблемы (например, метод класса, который вызывается free (видел это в Qt), или удаление выполняется) в заголовке, но новый в .lib, который должен быть связан (также видно в Qt)).
  • другие инструменты требуют, чтобы вы делали интерактивные снимки своего приложения и впоследствии сравнивали их. В моем подходе, приведенном выше, вы получаете автоматическое сообщение об утечке (никаких действий вручную не требуется, всегда в конце приложения, ...).

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

0 голосов
/ 09 февраля 2011

Непонятно, что вы имеете в виду, говоря, что вы перегружаете оператора new. Вы не можете перегрузить стандартный оператор, новый как таковой, вы можете заменить его только во время соединения. Когда вы заменяете его, вы теряете оригинальные, что является самым глупым дизайном, который я когда-либо видел. Замена тоже глобальная. На некоторых платформах вы можете обойти это с помощью трюков с компоновщиками для конкретной платформы (слабые символы).

Вы можете выполнять какие-то приемы поиска с помощью оператора на основе класса new, и, конечно, вы можете перегрузить оператор new для аргументов размещения, но я предполагаю, что вы не имеете в виду ни один из них.

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