Размещение нового, чтобы получить динамический размер
На основании этого вопроса: Распределение типа переменного размера
Будет ли следующая работа?
{
// size calculated.
std::auto_ptr<Base> p(new((void*)(new char[size])) Packet());
// Do Stuff
}
Где Packet - это структура POD, где последний член - массив. Идея состоит в том, чтобы разрешить динамически изменяемый массив (как мы делали это в C все эти годы назад)
struct Packet
{
// STUFF
int data[1];
}
2 ответа
Нет, это не работает: объекты, созданные в любой форме new
приняты дополнительные параметры, кроме std::nothrow
необходимо уничтожить явно, а память об этом позаботиться отдельно:
void* memory = operator new(size);
T* ptr = new(memory) T(args);
...
ptr->~T();
operator delete(memory);
Также обратите внимание, что способ выделения сырой памяти не является чем-то вроде new char[size]
: это конструкции char
объекты в памяти, которые должны быть уничтожены. Я понимаю, что ни конструирование, ни разрушение на самом деле ничего не делают со встроенными типами, но я довольно реализации, что разрешено что-то делать, и нет никакого разрешения пропустить эти деструкторы, насколько я знаю.
Наконец, обратите внимание, что вам также нужно построить int
Объекты и реализации разрешено помещать что-то после видимого конца структуры.
Я прошу прощения, если я пропустил важный момент, который каким-то образом скрыт в вопросе, и я не вижу его. Но относительно этой центральной линии:
std::auto_ptr<Base> p(new((void*)(new char[size])) Packet());
Вот что я могу сказать по этому поводу:
Вызов конструктора в конце должен быть
Packet
неPacket()
, хотя на практике компилятор может принять это как есть, и это может не иметь никакого значенияВнутреннее распределение
new char[size]
использует распределитель массиваnew []
, Ссылка CPP заявляет о выраженииnew [array_n]
:
Обратите внимание, что больше чем size_of( type) * array_n может быть выделено из-за дополнительной информации, закодированной компилятором (такой как размер массива, так как эта информация необходима для правильного разрушения объектов в массиве).
Теперь внешний вызов распределителя, new ((void*)(...))
, является экземпляром размещения new, который описан здесь следующим образом:
void* operator new ( std::size_t, void* ptr );
ничего не делает, возвращает ptr.
Другими словами, может случиться так, что призыв к new []
заставляет компилятор выделять больше памяти, чем строго требуется массиву, и кодировать информацию о размере в дополнительном пространстве. Однако, поскольку размещение new ничего не делает, оно не обрабатывает и не удаляет дополнительную информацию.
Но, так как использование std::auto_ptr
подразумевает, что это освобождение будет осуществляться с использованием delete
(а не delete []
), дополнительная информация не будет должным образом освобождена, следовательно, может произойти утечка памяти или еще хуже.
Изменить: Чтобы не полагаться только на ссылку CPP, соответствующие части стандарта C++ N3337 заключаются в следующем:
- § 18.6.1.2 гласит, что только
delete
должен использоваться для освобождения места, выделенногоnew
и соответственноdelete []
за пространство, выделенноеnew []
- § 18.6.1.3 прямо заявляет, что формы размещения
new
а такжеnew []
не выполнять никаких действий. Это означает, что ни один из них не может быть использован для "преобразования" пространства одного объекта в пространство массива.
Теперь, возможно, реальный вопрос заключается в том, будет ли применение нового предложения, предложенного в вопросе, действительным, если только delete []
был использован для освобождения места позже. Возможно, ответ не определен (что следует интерпретировать как эквивалент "Нет").