Переопределение новых и ведение журнала данных о вызывающем абоненте

Я пытаюсь написать профилировщик памяти, и до сих пор мне удалось заставить мои пользовательские функции работать для malloc, free, new и delete. Я пробовал использовать __FILE__ и __LINE__ для регистрации создателя внутри перегруженного нового метода, но (как и ожидалось) он просто дает подробную информацию о том, где находится перегруженная функция. Есть ли способ получить подробную информацию об отправителе перегруженных функций без внесения каких-либо изменений в существующий код тестируемого компонента (например, #define для malloc)?

Я использую следующую функцию:

void* operator new (size_t size)
{
    if(b_MemProfStarted)
    {
        b_MemProfStarted = false;
        o_MemLogFile << "NEW: " << "| Caller: "<< __FILE__ << ":"
                << __LINE__ << endl;
        b_MemProfStarted = true;
    }

    void *p=malloc(size);
    if (p==0) // did malloc succeed?
    throw std::bad_alloc(); // ANSI/ISO compliant behavior

    return p;
}

Bool b_MemProfStarted используется, чтобы избежать рекурсивных вызовов ofstream и map.insert.


person Gayan    schedule 08.09.2009    source источник


Ответы (2)


Ты можешь написать

new(foo, bar) MyClass;

В этом случае вызывается следующая функция

void*operator new(std::size_t, Foo, Bar){
    ...
}

Теперь ты можешь позвонить

new(__LINE__, __FILE__) MyClass;

и использовать данные с

void*operator new(std::size_t, unsigned line, const char*file){
    ...
}

Добавление макроса

#define new new(__LINE__, __FILE__)

к отслеживаемому коду будет улавливать большинство вызовов без необходимости изменения исходного кода.

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

person B.S.    schedule 08.09.2009
comment
Поскольку new является ключевым словом, попытка переопределить его с помощью макроса является неопределенным поведением (за исключением специальных расширений компилятора). Я предпочитаю условно определять макрос DEBUG_NEW_PLACEMENT для «обычных» news и оставлять только явное operator new и специальное размещение new. Однако это все еще не очень хорошее решение. - person CB Bailey; 08.09.2009
comment
void operator new (std :: size_t, unsigned line, const char file) завершится ошибкой, потому что new просто принимает size_t. Нельзя использовать #define new new (LINE, FILE) и переопределение оператора вместе, так как он попытается заменить новый в определении функции переопределения. void operator new (std :: size_t) - ›void operator new (LINE, FILE) / * рекурсивный? * / (std :: size_t) - person Gayan; 08.09.2009
comment
@ Чарльз Бейли - Не могли бы вы уточнить? Я не знаком с DEBUG_NEW_PLACEMENT. Я попробовал #define new (size) My_New (size, FILE, LINE), но, похоже, это не вызывается при выполнении нового - person Gayan; 08.09.2009
comment
@Gayan Вы можете определить оператор new с дополнительными параметрами. Можно даже перегрузить ими. Дополнительные параметры должны быть переданы при вызове new, как показано выше. Вы, конечно, должны убедиться, что у вас не определен макрос при записи фактической перегрузки. - person B.S.; 08.09.2009
comment
При использовании вашей замещенной новой функции вместо обычной новой вы не включаете параметр size_t. Определения сделают всю работу по добавлению дополнительных параметров. - person Alan; 09.09.2009

Нет, ты не можешь

#define new new(__FILE__, __LINE__)

но вы можете:

#define DEBUG_NEW new(__FILE__, __LINE__)
#define new DEBUG_NEW

посмотрите: http://sourceforge.net/projects/nvwa/

person teZeriusz    schedule 08.09.2009