Выделите vs создайте массив int, используя оператор new и размещение new

#c #new-operator #delete-operator #placement-new

Вопрос:

Здравствуйте, чтобы понять больше placement new , operator new , выражение delete .. и отделить инициализацию от построения, я попробовал этот пример:

 int main(){

    int* p = static_cast<int*>(operator new[](10 * sizeof(int)));
    p = new(p)int[10];

    for(int i = 0; i != 10;   i)
        p[i] = i * 7;

    for(int i = 0; i != 10;   i)
        std::cout << p[i] << ", ";
    operator delete[](p);

}
 
  • Я скомпилировал его и запустил, и он отлично работает, и проверил его с помощью Valgrind на наличие утечек памяти, и ничего плохого не сообщается. Так это как отделить инициализацию от распределения?
  • В чем я не уверен, так это в том, что я использовал оператор delete для освобождения памяти динамического массива, но не уничтожил его (удаление размещения отсутствует). Так есть ли что-то плохое в моем коде?

Ответ №1:

Как вы заметили, нет placement delete . При использовании placement new вам придется вызывать деструкторы вручную , например:

 void* mem = operator new[](10 * sizeof(T));
T* p = new(mem) T[10];
...
for(int i = 0; i < 10;   i)
    p[i].~T();
operator delete[](mem);
 

Где T указан желаемый тип элемента.

Вызов деструкторов не очень важен для типов модулей, например int , но это важно для типов, отличных от модулей , например std::string , и т. Д., Чтобы избежать утечек.

Комментарии:

1. Вы должны быть осторожны с подобным кодом. Некоторые реализации размещения new [] добавляют префикс «количество массивов» к массиву вновь построенных объектов, что исключает вычисление пространства для указанного массива. Вы также предполагаете, что возвращаемое значение new(p) T[10] равно p . Опять же, это не всегда верно. Из-за этого лучше вызывать форму размещения без массива new в цикле. Тогда (при условии, что вы все сделаете правильно) ничего не может пойти не так.