2013-05-24 1 views
8

Я экспериментирую с обновлением нашего объединенного блока распределения памяти с фиксированным блоком, чтобы использовать возможности типа C++ 11.Можно ли переопределить глобальный новый оператор на основе свойств типа выделенного объекта?

В настоящее время можно заставить любое выделение любого объекта в любом месте, чтобы быть отправленной в правильный пул путем переопределения the global new operator традиционным способом, например

void* operator new (std::size_t size) 
{ // if-cascade just for simplest possible example 
    if (size <= 64) { return g_BlockPool64.Allocate(); } 
    else if (size <= 256) { return g_BlockPool256.Allocate(); } 
    // etc .. else assume arguendo that we know the following will work properly 
    else return malloc(size); 
} 

Во многих случаях мы могли бы улучшить производительность еще больше, если объекты могут быть отправлены в разные пулы в зависимости от типов типов, таких как is_trivially_destructible. Возможно ли создать шаблонный глобальный новый оператор, который знает о распределенном типе, а не только запрошенный размер? Что эквивалентно

template<class T> 
void *operator new(size_t size) 
{ 
    if (size < 64) 
    { return std::is_trivially_destructible<T>::value ? 
      g_BlockPool64_A.Allocate() : 
      g_BlockPool64_B.Allocate(); } // etc 
} 

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

Foo *p = new (mempool<Foo>) Foo(); 

слишком громоздким и люди забывают использовать его.

+1

Уютная идея. Хотя как тривиально разрушаемая помощь менеджеру памяти? Менеджер не заботится о строительстве и разрушении. – GManNickG

+0

@GManNickG Если все тривиально разрушаемые объекты попадают в один и тот же пул, мы можем отменить их в массовом порядке, просто разделив страницу памяти и вообще не называя каких-либо деструкторов. Это один вызов ОС вместо миллионов освобождений. Полезно, когда все распределения для куска уровня идут в блок, и вы можете просто выбросить вещь за борт, покидая эту область. Уже существуют другие механизмы, позволяющие людям удерживать указатели в этом блоке за всю их жизнь. – Crashworks

+0

Нет. Кроме того, 'return :: new (size);' бесконечная рекурсия. – aschepler

ответ

3

Короткий ответ - нет. Функции распределения/отмены имеют следующие подписи:

void* operator new(std::size_t); 
void* operator new[](std::size_t); 
void operator delete(void*); 
void operator delete[](void*); 

Большинство отклонений от этих подписей приведет к вашей функции не используется вообще. В типичной реализации вы в основном заменяете реализации по умолчанию на уровне компоновщика - т. Е. Существующая функция имеет какое-то определенное искаженное имя. Если вы предоставляете функцию с именем, которое искажает идентичный результат, оно будет привязано вместо этого. Если ваша функция не работает с тем же именем, она не будет связана.

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

Смежные вопросы