Кое да използвам - оператор new или operator new[] - за разпределяне на блок необработена памет в C++?

Моята C++ програма се нуждае от блок неинициализирана памет и void* указател към този блок, за да мога да го предам на библиотека на трета страна. Искам да предам контрола върху живота на блока на библиотеката, така че не искам да използвам std::vector. Когато библиотеката приключи с блока, тя ще извика обратно извикване, което трябва да осигуря и което ще освободи блока. В C бих използвал malloc() и по-късно free().

В C++ мога да извикам съответно ::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
OP не говори за 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

Моята инсталация на Wordpress (2.9.2) прави това автоматично - каноничните URL адреси са вградени в Wordpress от известно време. Може би вашият плъгин е деактивиране на тази функция?

- person ; 23.03.2010
comment
Е, предложението просто да използвам new char[] предполага, че трябва да използвам ::operator new[]. - person sharptooth; 26.03.2010
comment
@sharptooth: Вярвам, че той казва, че трябва да използвате нов израз, вместо да извиквате оператор new директно, без да се опитвате да внушите нещо за оператор new срещу оператор new[]. Вие обаче значително променихте въпроса, тъй като, както е написано сега, вие нямате избор как да разпределя библиотеката на трета страна, вместо вие да имате едноличен контрол, както сте имали преди. - person ; 26.03.2010
comment
@Roger Pate: Да, напълно разбирам отговора му. Все пак не искам да използвам оператора new просто за да избегна кастинг от char* към void* и обратно, дори ако static_cast ще свърши работата безплатно. Както и да е, изразът new[] предполага ::operator new[] и това повече или по-малко отговаря на въпроса ми. - person sharptooth; 26.03.2010

Предимството на C++ new операторите пред C malloc() и free() е, че първият хвърля изключение, ако няма достатъчно памет, вместо да връща 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

за разпределяне на памет към масив/списък използвайте нов [], различен от този използвайте нов...

person Mihir Mehta    schedule 23.03.2010