Краткий ответ:
Нет прямой поддержки для этого использования. Если вы перегружаете новый с другой подписью, компилятор считает это перегрузкой нового (не размещения нового) и добавляет свой собственный код учета. Нет никакого способа (я могу найти) сказать компилятору «размотать вашу бухгалтерию и вызвать мою перегрузку удаления, соответствующую этой подписи» - он будет вставлять только код для размотки бухгалтерии при вызове void operator delete(void* p)
или void operator delete[](void* p)
.
Если вы переопределяете новое новой подписью, компилятору нравится, когда вы определяете удаление с соответствующей подписью в случае исключений во время новой - это единственный раз, когда он используется.
Нет удаления размещения в том смысле, что оно не вызывается, но оно определено в случае исключений (ничего не делать).
Длинный ответ:
Эта тема поднимает некоторые интересные моменты:
- Что именно
void* operator new[](size_t sz, Allocator* a)
перегружает?
- Есть или нет "удаление места размещения".
- Как можно вызвать
void operator delete[](void* p, Allocator* a)
таким образом, как компилятор вставляет свою завершающую работу по бухгалтерскому учету?
Пункт 1: Много разговоров о перегрузке размещения новых. Учитывая, что компилятор вставляет код бухгалтерского учета, он должен придерживаться мнения, что void* operator new[](size_t sz, Allocator* a)
объявляет перегрузку (не размещение) новой. Он никогда не вставит бухгалтерский код для размещения новых, потому что смысл размещения новых заключается в том, что вы сами с этим справляетесь.
Пункт 2: Р.Е. "нет такой вещи, как удаление размещения", вы найдете что-то, что ужасно похоже на это (и прокомментировано как таковое), например, VS2k8 новый заголовок. Это просто заглушка, используемая в тех случаях, когда во время размещения возникает исключение. Тем не менее, представляется верным, что вы не можете вызвать удаление размещения значимым образом.
Пункт 3: Если есть способ, я не могу его найти. Это суть проблемы.
С точки зрения практического решения проблемы, это похоже на провал.
например:
//intention: user provides memory pool, compiler works out how many bytes required
//and does its own book-keeping, as it would for a void* operator new[](size_t sz) overload
//calling syntax: CObj* pMyArr = new(pMyMemPool) CObj[20];
void* operator new[](size_t sz, IAlloc* pMemPool)
{ return pMemPool->alloc(sz); }
//problem: don't know the syntax to call this!
//e.g. delete[](pMyMemPool) pMyArr is syntax error
void* operator delete[](void* p, IAlloc* pMemPool)
{ return pMemPool->free(p); }
//nb: can be called as operator delete(pMyArr, pMyMemPool);
//but compiler does not finish its book-keeping or call dtors for you in that case.
Обратите внимание, что эта асимметрия существует и для не-массива new и delete. Однако, поскольку (эмпирически) рассматриваемый компилятор не ведет никакой дополнительной бухгалтерии, его можно заставить работать. Опять же, если это закреплено в стандарте, я не знаю.
void* operator new(size_t sz, IAlloc* pMemPool)
{ return pMemPool->alloc(sz); }
//don't know syntax to get this called by compiler!
void operator delete(void* p, IAlloc* pMemPool)
{ pMemPool->free(p); }
//is ok though, can work around
template<class T> void tdelete(void* p, IAlloc* pMemPool)
{
//no problems, p points straight at object
p->~T();
operator delete(p, pMemPool);
//OR just
pMemPool->free(p);
}
void* operator new[](size_t sz, IAlloc* pMemPool)
{ return pMemPool->alloc(sz); }
//again, don't know syntax to end up here.
void operator delete[](void* p, IAlloc* pMemPool)
{ pMemPool->free(p); }
//can't work around this time!
template<class T> void tarrdelete(void* p, IAlloc* pMemPool)
{
//problem 1: how many to dtor?
for(int i=0; i<???; ++i)
{ reinterpret_cast<T*>(p+i)->~T(); }
//problem 2: p points at first element in array. this is not always the address
//that was allocated originally.
pMemPool->free(?);
//as already explained by OP, no way to tell if p is address allocated or
//address allocated+4 bytes, or something else altogether. this means no way to know what address to un-alloc or how many dtors to call.
}
Наконец, я сообщу об этом. - перегрузки без расширенного списка параметров работают:
//sz may include extra for book-keeping
void* operator new[](size_t sz)
{ return GAlloc->alloc(sz); }
//works fine, compiler handled book-keeping and p is the pointer you allocated
void operator delete[](void* p)
{ return GAlloc->free(p); }
Сводка : существует ли синтаксис, позволяющий вызывать перегрузку удаления с расширенным списком параметров, с включенной «магией» компилятора. Или есть способ добавить параметры для размещения новых путем переопределения?
Подозреваемый ответ : Нет.
Следствие : Вы не можете отклониться от 6 встроенных новых подписей с полной свободой. Это приводит к перегрузке нового, при этом ведется бухгалтерский учет, сгенерированный компилятором, но нет доступа к соответствующему удалению для отмены бухгалтерского учета.
Предостережение : Вы можете отклониться от встроенных подписей, но только для того, чтобы ввести код, который вам не нужно снова обрабатывать при удалении (например, инструментарий). Если вы перейдете к версии void* operator new(size_t s)
для выделения, удаление все равно будет работать как обычно.
(Некоторые констатации фактов взяты из экспериментов в отладчике и могут применяться только к MSVC8 (cl9). OP сидит рядом со мной.)