Что использовать - оператор new или оператор new[] - для выделения блока необработанной памяти в C++?

Моей программе на C++ нужен блок неинициализированной памяти и указатель void* на этот блок, чтобы я мог передать его сторонней библиотеке. Я хочу передать управление временем жизни блока библиотеке, поэтому не хочу использовать std::vector. Когда библиотека закончит работу с блоком, она вызовет обратный вызов, который я должен предоставить, и это освободит блок. В C я бы использовал malloc(), а позже free().

В С++ я могу вызвать ::operator new или ::operator new[] и ::operator delete или operator delete[] соответственно позже:

void* newBlock = ::operator new( sizeOfBlock );
// then, later
::operator delete( newBlock );

Похоже, что и ::operator new, и ::operator new[] имеют одинаковую сигнатуру и одинаковое поведение. То же самое для ::operator delete и ::operator delete[]. Единственное, что я не должен делать, это спаривать operator new с operator delete[] и наоборот - неопределённое поведение. Кроме того, какую пару я выбираю и почему?


person sharptooth    schedule 23.03.2010    source источник
comment
Я предполагаю, что вы знаете, что вы должны использовать std::vector<char>, бла-бла-бла.   -  person GManNickG    schedule 23.03.2010
comment
Почему вы думаете, что с std::vector у вас нет контроля над временем жизни объекта?   -  person Martin York    schedule 23.03.2010
comment
Вопрос не ясен. У вас есть контроль над освобождением или вы передаете эту ответственность библиотеке? Все ответы до этого редактирования не соответствуют измененным требованиям.   -  person    schedule 26.03.2010
comment
@Roger Pate: разъяснено об освобождении.   -  person sharptooth    schedule 26.03.2010


Ответы (4)


Используйте new с одним объектом и new[] с массивом объектов. Так, например:

int* x = new int; // Allocates single int
int* y = new int[5]; // Allocates an array of integers

*x = 10; // Assignment to single value
y[0] = 8; // Assignment to element of the array

Если все, что вы делаете, это выделяете буфер памяти, то выделите массив char как в:

int bufferlen = /* choose a buffer size somehow */
char* buffer = new char[bufferlen];
// now can refer to buffer[0] ... buffer[bufferlen-1]

Однако в C++ вы действительно должны использовать std::vector для произвольных массивов, и вы должны использовать std::string для символьных массивов, которые должны интерпретироваться или использоваться как строки.

Нет причин вызывать ::operator new или ::operator new[] явно, а не использовать обычный синтаксис для этих вызовов. Для POD и примитивных типов (например, char) инициализация не выполняется. Если вам нужно получить буфер void*, просто используйте static_cast для преобразования char* в void*.

person Michael Aaron Safyan    schedule 23.03.2010
comment
ОП не говорит о new int и new int[5], а конкретно вызывает функции с заданными именами, например. void* p = operator new(50); против void* p = operator new[](50);. - person ; 23.03.2010
comment
Ваше обновление немного неправильно. Существует разница между new int и new int() (последний объект гарантированно инициализируется нулем), и аналогично для любого типа POD. Для new[] также работает один особый случай: new int[5](). - person ; 23.03.2010
comment
@ Роджер, это правильно; однако в приведенном мной синтаксисе инициализация не выполняется. - person Michael Aaron Safyan; 23.03.2010
comment
Вот почему я сказал слегка, в частности: для POD и примитивных типов (например, char) инициализация не будет выполняться. Вы не поясняете, что new int имеет другую семантику, чем new int(), но характеризуете весь обычный синтаксис. - person ; 23.03.2010
comment
Ну, предложение просто использовать new char[] подразумевает, что я должен использовать ::operator new[]. - person sharptooth; 26.03.2010
comment
@sharptooth: я полагаю, он говорит, что вы должны использовать новое выражение, а не вызывать оператор новый напрямую, не пытаясь что-либо подразумевать относительно оператора новый против оператора новый []. Однако вы значительно изменили вопрос, потому что, как написано сейчас, у вас нет выбора в том, как освобождается сторонняя библиотека, вместо того, чтобы иметь единоличный контроль, как раньше. - person ; 26.03.2010
comment
@Roger Pate: Да, я полностью понимаю его ответ. Тем не менее я не хочу использовать оператор new просто для того, чтобы избежать приведения от char* к void* и обратно, даже если static_cast выполнит эту работу бесплатно. В любом случае утверждение new[] подразумевает ::operator new[], и это более или менее отвечает на мой вопрос. - person sharptooth; 26.03.2010

Преимущество операторов C++ new по сравнению с операторами malloc() и free() в C состоит в том, что первый создает исключение, если памяти недостаточно, а не возвращает NULL.

Что касается выбора new(size) и new[] для символьных буферов, я бы поддержал последнее, так как это вряд ли удивит людей, поддерживающих код позже, то есть char* buf = new char[size] и delete[] buf.

Значения в буфере не будут инициализированы, и нет проверки диапазона — вам нужно создать хороший объект C++, чтобы сделать это за вас, или использовать существующий объект, такой как std::vector или std::string.

person Will    schedule 23.03.2010

На вопрос нельзя ответить разумно.

Во-первых, сказано, что программе "нужен" блок неинициализированной памяти, но из приведенного примера кода кажется, что программе "нужен" блок неинициализированной и НЕТИПИРОВАННОЙ памяти, что кажется не очень C++ или OO.

Во-вторых, std::vector дает единоличный и автоматический контроль над блоком типизированной памяти, размер которого может меняться или не меняться в зависимости от его использования. Вы можете потерять этот контроль, если экземпляр std::vector создается в куче и отслеживается с помощью необработанных указателей, как и для любого другого объекта C или C++, такого как блок памяти void*.

В-третьих, каково предполагаемое использование этого блока памяти? Ответ на этот вопрос может диктовать или не диктовать использование оператора new или оператора new[]. Есть ли в дизайне этой программы единая интерпретация этого блока памяти? Какая семантика владения вам требуется, если таковая имеется? И т. д. и т. д.

person Sam    schedule 23.03.2010

для выделения памяти массиву/списку используйте new[], кроме того, что используйте new...

person Mihir Mehta    schedule 23.03.2010