Intereting Posts
Ошибки графической библиотеки Stroupstrup Является `использование пространства имен foo;` бесполезным? Как разрешить предупреждение компилятора «неявное объявление функции memset» Производительность std :: function по сравнению с необработанным указателем функции и void * this? C ++: push () vack () vs emplace () Заполнение кода Vim сопоставить адрес строкового литерала с строковым литералом, путем parsingа программы ELF C ++ Существуют ли какие-либо инструменты автоматического преобразования для переноса кода на C ++ на 64-разрядный? std :: unique_ptr, удаления и API Win32 Как вы получаете файл на C ++? Использует ли вектор булевых значений медленнее, чем динамический битрейт? Есть ли какой-либо показатель производительности для Thrift на HBase? Могу ли я ссылаться на предыдущие члены списка инициализаторов? Ограничивает ли extern «C» ограничение на мой код? cl :: vector vs std :: vector: поведение iteratorа

Макросменить оператор C ++ new

Можно ли создавать macros для замены всех форм operator new с перегрузками, которые include дополнительные аргументы … скажем, __FILE__ и __LINE__ ?

Проблема состоит в том, что operator new может быть закодирован с круглыми скобками или без них, поэтому:

К сожалению, это ошибка при попытке объявить два макроса с одним и тем же идентификатором , даже если они имеют разные типы , поэтому следующее:

 #define new new(__FILE__, __LINE__) #define new(A) new (A, __FILE__, __LINE__) // Error: "new" already defined 

Поскольку я использую g ++, я надеялся, что использование их синтаксиса вариативных макросов даст успех, но, к сожалению, нет. Следующие:

 #define new(...) new(__FILE__, __LINE__, ## __VA_ARGS__) 

соответствует только new(xyx) A() , а не new A() .

Я знаю, что были написаны очерки о том, почему это невозможно, но я чувствую, что я настолько близок, что должен быть способ. Есть ли что-то очевидное, что мне не хватает?

Вот что я использую:

В new.cpp

 const char* __file__ = "unknown"; size_t __line__ = 0; void* operator new(size_t size) { void *ptr = malloc(size); record_alloc(ptr,__file__,__line__); __file__ = "unknown"; __line__ = 0; return ptr; } void delete(void *ptr) { unrecord_alloc(ptr); free(ptr); } 

Для компактности я оставляю другие определения new и delete. «record_alloc» и «unrecord_alloc» – это функции, которые поддерживают связанный список структуры, содержащий ptr, строку и файл).

в new.hpp

 extern const char* __file__; extern size_t __line__; #define new (__file__=__FILE__,__line__=__LINE__) && 0 ? NULL : new 

Для g ++ «новый» расширяется только один раз. Ключ – это «&& 0», что делает его ложным и вызывает использование нового нового. Например,

 char *str = new char[100]; 

расширяется препроцессором до

 char *str = (__file__="somefile.c",__line__=some_number) && 0 ? NULL : new char [100]; 

Таким образом, записываются номер файла и строки, и вызывается ваша пользовательская новая функция.

Это работает для любой формы нового – пока существует соответствующая форма в new.cpp

Вы должны проверить эту замечательную запись в блоге моим коллегой Кальвином. Недавно у нас была ситуация, когда мы хотели включить этот тип исправлений, чтобы связать утечки памяти с линией, выделенной ими в assemblyх диагностики / отладки. Это интересный трюк

http://blogs.msdn.com/calvin_hsia/archive/2009/01/19/9341632.aspx

3.7.4 Динамическая длительность хранения

2 Библиотека предоставляет определения по умолчанию для глобальных функций распределения и удаления. Некоторые функции глобального распределения и освобождения являются сменными (18.5.1). Программа C ++ должна предоставлять не более одного определения сменной функции распределения или освобождения. Любое такое определение функции заменяет версию по умолчанию, предоставленную в библиотеке (17.6.4.6) […]

17.6.4.6 Функции замены

  1. Программа C ++ может предоставить определение для любой из восьми сигнатур функций динамической памяти, объявленных в заголовке (3.7.4, раздел 18):

    • оператор new (std :: size_t)
    • operator new (std :: size_t, const std :: nothrow_t &)
    • operator new [] (std :: size_t)
    • operator new [] (std :: size_t, const std :: nothrow_t &)
    • оператор delete (void *)
    • оператор delete (void *, const std :: nothrow_t &)
    • оператор delete [] (void *)
    • оператор delete [] (void *, const std :: nothrow_t &)

Надеюсь, что это разъясняет, что такое законная перегрузка, а что нет.

Это может представлять интерес для нескольких здесь:

 #define delete cout << "delete called at: " << __LINE__ << " of " << __FILE__ << endl, delete using namespace std; void *operator new(size_t size, ostream& o, char *f, unsigned l) { o << "new called at: " << l << " of " << f << endl; return ::new char[size]; } int main() { int *a = new(cout, __FILE__, __LINE__) int; delete a; } 

Caveat Lector : То, что я делаю здесь, это Bad Thing (TM), чтобы сделать - перегружать новый / удалить глобально.

Вы не говорите, какой компилятор вы используете, но, по крайней мере, с GCC, вы можете переопределить новый и зарегистрировать адрес вызывающего абонента, а затем перевести его в файл / строку с помощью addr2line (или использовать библиотеку BFD для этого немедленно).

Я обнаружил, что следующая библиотека « nvwa » очень полезна для отслеживания утечек памяти «new / delete» – посмотрите на файл «debug_new» на примерах или просто используйте «как есть».

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

Нет, нет.

Вы можете сделать это в плохие старые дни malloc()/free() но не для new .

Вы можете заменить распределитель памяти глобальным переопределением new оператора, но вы не можете вводить специальные переменные, о которых вы говорите.