Размещение нового, чтобы получить динамический размер

На основании этого вопроса: Распределение типа переменного размера

Будет ли следующая работа?

{
    // 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());

Вот что я могу сказать по этому поводу:

  1. Вызов конструктора в конце должен быть Packetне Packet(), хотя на практике компилятор может принять это как есть, и это может не иметь никакого значения

  2. Внутреннее распределение 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 [] был использован для освобождения места позже. Возможно, ответ не определен (что следует интерпретировать как эквивалент "Нет").

Другие вопросы по тегам