C ++ на месте строительства & amp; последующее уничтожение: как мне получить правильный указатель?

Отказ от ответственности: Это нюансированный вопрос C ++, тесно связанный со строгим чтением спецификации C ++.

В C ++ традиционный способ использования конструкции на месте:

void * pStorage = myPooledAllocationFunction ( /*pool number*/1 ) ; // allocate from pool number 1, for example
MyClass * p = new (pStorage) MyClass () ;

Однако важно отметить, что reinterpret_cast<void*> ( p ) не обязательно равен pStorage,

Примечание: я был в замешательстве, когда только что прочитал, что новое место размещения может сделать гораздо больше, так как на самом деле просто говорит: «Пожалуйста, позвоните operator new с этими дополнительными аргументами »и традиционным способом его использования просто имеет реализацию по умолчанию в C ++.

Я считаю, что традиционный метод освобождения этого вновь созданного объекта заключается в следующем:

p->~MyClass() ;
myPoolDeallocationFunction ( /*pool number*/1 ) ; // deallocate pool 1 in its entirety

Что предполагает, что вы в состоянии сделать это. Но что, если вы не? Что если вам нужно вернуть исходный указатель из p?

Это действительно?

p->~MyClass() ;
myPooledDeallocationFunction ( static_cast<void*> ( p ) ) ;

Спецификация C ++ (C ++ 2003: 5.2.9.10) указывает, что это действительно для использования static_cast конвертировать из MyClass* в void* а затем вернуться к MyClass*,

Есть еще одно упоминание (C ++ 2003: 3.8.5) в связи с этим, указав, что вы можете, после вызова деструктора, но до освобождения памяти, выполнить очень специфический набор вещей с этим указателем. Для наших целей все, что нас волнует, это то, что оно включает void* (который действителен, потому что старый указатель «указывает на действительную память»).

Это не говорит, что если void* был оригинал void* используется для строительства на месте.

Так: как получить исходный указатель, используемый для создания на месте из результирующего указателя?

3

Решение

Ты можешь использовать dynamic_cast<void*> извлечь исходный указатель из базового класса. Полученный указатель будет всегда указать на самый производный класс, a.k.a. весь объект.

Насколько я знаю, это незаконно для pStorage а также p быть разными адресами.

3

Другие решения

Похоже, это академический вопрос, который требует педагогического ответа.

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

(Затем замаскируйте соответствующие младшие биты p, чтобы получить оригинальную новую цель.)

2

Большинство компиляторов используют действительно простую реализацию размещения new, как указано в 11.2.4 в «Язык программирования C ++».

Например VS — 2013:

 #ifndef __PLACEMENT_NEW_INLINE
#define __PLACEMENT_NEW_INLINE
inline void *__CRTDECL operator new(size_t, void *_Where) _THROW0()
{   // construct array with placement at _Where
return (_Where);
}

Но в книге нет эксплицитно объяснил, должен ли возврат нового размещения обязательно совпадать с переданным указателем.

Итак, AFAIK, это должно работать. И dynamic_cast<void*> По указанию @Puppy для получения оригинального указателя выглядит отличная идея.

Но я хотел бы поговорить о явном вызове деструктора и о том, что говорит об этом Страуструп:

«Обратите внимание, что явных вызовов деструкторов следует избегать, кроме как в реализации ресурса
классы управления. «

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

Обычно я думаю, что нахождение подобных сбоев или вопросов в программировании на C ++ связано с некоторыми недостатками дизайна (конечно, я не ставлю под сомнение дизайн того, что вы делали), но, возможно, их следует использовать в качестве сигналов, чтобы думать о том, что именно мы делаем. делают.

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

1
По вопросам рекламы [email protected]