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

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

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

{
    // 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 ]

1 голос
/ 15 марта 2012

Нет, это не работает: объекты, построенные в любой форме new с дополнительными параметрами, отличными от std::nothrow, должны быть явно уничтожены, а память была сохранена отдельно:

void* memory = operator new(size);
T* ptr = new(memory) T(args);
...
ptr->~T();
operator delete(memory);

Также обратите внимание, что способ выделения необработанной памяти - это , а не , что-то вроде new char[size]: это создает char объектов в памяти, которые необходимо уничтожить. Я понимаю, что ни конструирование, ни разрушение на самом деле ничего не делают со встроенными типами, но я довольно реализации, что разрешено что-то делать, и нет никакого разрешения пропустить эти деструкторы, насколько я знаю.

Наконец, обратите внимание, что вам также необходимо сконструировать объекты int, и реализации разрешено помещать что-то после видимого конца структуры.

0 голосов
/ 15 марта 2012

Я прошу прощения, если я пропустил важный момент, который каким-то образом скрыт в вопросе, и я не вижу его.Но относительно этой центральной строки:

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 (тип) * array_n из-за закодированной дополнительной информациикомпилятором (таким как размер массива, так как эта информация необходима для правильной деструкции объектов в массиве).

Теперь внешний вызов распределителя new ((void*)(...))экземпляр размещения нового , который описан здесь следующим образом:

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...