Как правильно заменить глобальные операторы new & delete - PullRequest
53 голосов
/ 18 ноября 2011

Прежде всего, было как минимум 4-5 тем с похожей темой на SO. Я читаю каждый из них, и я не чувствую, что они действительно помогают мне с этим конкретным вопросом. Если кто-то найдет повторяющийся вопрос, я прошу прощения. Я выполнил свою часть поиска еще до того, как опубликовал это, так как это кажется очень распространенным вопросом.

Я использую Visual Studio .NET 2003 в Windows 7.

У меня есть собственные перегрузки new / delete, которые указывают на мои собственные пользовательские вызовы malloc () и free () для диагностики. Мои новые / удаленные перегрузки находятся в заголовочном файле, который я включил в несколько файлов.

Проблема в том, что кодовая база в значительной степени спагетти, и нет простого способа убедиться, что эти перегрузки используются всем. Есть сторонние библиотеки, которые являются черным ящиком. Мы также используем STL везде.

В своих тестах я обнаружил, что STL все еще смешивает вызовы с моими собственными вызовами new / delete и стандартными вызовами MSVC new / delete.

Кажется нереальным включать мой заголовочный файл в тысячи других файлов, это займет слишком много времени. Кто-нибудь может предложить несколько советов о том, как правильно и эффективно перегрузить новое / удалить глобально, чтобы все использовали мой собственный менеджер памяти?

Ответы [ 2 ]

74 голосов
/ 18 ноября 2011

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

// optional_ops.cpp

void * operator new(std::size_t n) throw(std::bad_alloc)
{
  //...
}
void operator delete(void * p) throw()
{
  //...
}

В принципе, нет необходимости в каких-либо заголовочных файлах для объявления этих функций (operator new, operator delete), поскольку объявления *1013* этих двух функций уже жестко закодированы в язык, если вы будете , Однако имена std, std::bad_alloc и std::size_t предварительно объявлены , а не , поэтому вы, возможно, захотите включить <new> или какой-либо другой заголовок для предоставления этих имен.

В C ++ 11 и более поздних версиях вы можете альтернативно использовать decltype(sizeof(0)), чтобы получить размер первого параметра таким образом, чтобы не требовалась какая-либо библиотека. C ++ 11 также имеет более простую модель исключений без спецификаций динамических исключений (которые были окончательно удалены из языка полностью в C ++ 17).

void * operator new(decltype(sizeof(0)) n) noexcept(false)
{
  //...
}
34 голосов
/ 18 ноября 2011

Также добавьте эти строки:

void *operator new[](std::size_t s) throw(std::bad_alloc)
{
    // TODO: implement
    return NULL;
}
void operator delete[](void *p) throw()
{
    // TODO: implement
}
...