2010-03-22 3 views
30

Я хочу создать на C++ массив объектов без использования STL.C++, массив объектов без <vector>

Как это сделать?

Как я могу создать массив Object2, у которого нет конструктора без аргументов (конструктор по умолчанию)?

+10

Из интереса, почему бы вам не использовать stl? – Sean

+0

@osgx: Почему бы просто не определить конструктор по умолчанию? – kennytm

+4

@KennyTM Это нехорошее решение. Многие классы не могут и не должны быть по умолчанию конструктивными. – 2010-03-22 15:32:22

ответ

33

Если тип в вопросе имеет никаких аргументов конструктора, используйте new[]:

Object2* newArray = new Object2[numberOfObjects]; 

Не забудьте позвонить delete[], когда вам больше не нужен массив:

delete[] newArray; 

Если это Безразлично 't использовать такой конструктор operator new для выделения памяти, затем называть конструкторы на месте:

//do for each object 
::new(addressOfObject) Object2(parameters); 

Опять же, не забудьте освободить массив, когда он вам больше не нужен.

+3

Object2 не имеет значения по умолчанию c'tor. – kennytm

+0

вы разбили мой мозг этой конструкцией: :: new (address) Object2 (параметры); – Andrey

+7

@ Андрей: Это простое старое размещение нового. – sharptooth

0

Если конструктор по умолчанию недоступен, вам понадобится массив указателей, а затем цикл над этим массивом для инициализации каждого указателя.

+2

Это вряд ли Быстро: проблемы с распределением и недостатки кэша вероятны. –

5
Object2 *myArray[42]; 
for (int i = 0; i < 42; i++) 
{ 
    myArray[i] = new Object2(param1, param2, ...); 
} 

Позже вы должны будете пройти через массив и освободить каждого члена в отдельности:

for (int j = 0; j < 42; j++) 
{ 
    delete myArray[j]; 
} 
+0

'Object2 myArray [42];' этот шаг не будет работать, если только у Object2' нет конструктора по умолчанию (объявленного пользователем или иным образом). –

+1

@Charles Bailey. Yup, I заметил, что второй после того, как я разместил его, и изменил его на массив указателей. –

+0

heeey. Это не массив объектов, это массив указателей! – osgx

0

Очевидный вопрос, почему вы не хотите использовать STL.

Предполагая, что у вас есть причина, вы должны создать массив объектов с чем-то вроде Obj * op = new Obj[4];. Просто не забудьте избавиться от него delete [] op;.

Вы не можете сделать это с объектом без конструктора, который не принимает аргументы. В этом случае я думаю, что лучше всего вы можете выделить некоторую память и использовать новое место размещения. Это не так просто, как другие методы.

+0

Я пытаюсь реализовать stl-подобные структуры с нуля. будет не вектором, а smth, как B-дерево векторов постоянной длины, и я хочу полный контроль, поэтому я хочу реализовать его целиком один. – osgx

3

Используйте массив указателей на Object2:

std::tr1::shared_ptr<Object2>* newArray = new shared_ptr<Object2>[numberOfObjects]; 
for(int i = 0; i < numberOfObjects; i++) 
{ 
    newArray[i] = shared_ptr<Object2>(new Object2(params)); 
} 

Или, в качестве альтернативы, без использования shared_ptr:

Object2** newArray = new Object2*[numberOfObjects]; 
for(int i = 0; i < numberOfObjects; i++) 
{ 
    newArray[i] = new Object2(params); 
} 
+1

Как отмечают другие, это добавляет много накладных расходов на использование памяти (us это куча блоков кучи, каждый из которых стоит кучу кучи) и разбивает пространственную локальность. –

+0

@Ben Voigt, что вы имеете в виду «куча блоков кучи»? Сколько времени занимает куча кучи и требуется ли для каждого нового объекта Object2 (params)? – osgx

+0

Размер заголовка кучи зависит от параметров компилятора и от того, используется ли куча отладки или нет, но для реализаций, с которыми я знаком, это _minimum_ из 2 * sizeof (void *), который составляет 8 байтов для 32- битный процесс. Каждый вызов to :: new, :: new [] или malloc должен содержать пробел для кучи кучи внутри блока кучи, который он возвращает, и обратный адрес почти гарантированно будет кратным sizeof (void *). Было бы необычно, если новый char() фактически выделил бы 64 байта или более в сборке отладки, который имеет проверки для переполнения, переполнения, записи, выполняющей выделение, и т. Д. –

4

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

10

Предполагая, что ваш класс Base и у вас есть один аргумент конструктор

Base arr[3] = {Base(0), Base(1), Base(2)} ; 
+1

Это лучшее решение, если вы знаете размер массива во время компиляции, если не идете с вектором. – smerlin

+0

Я знаю размер только при создании контейнера. – osgx

13
// allocate memory 
Object2* objArray = static_cast<Object2*>(::operator new (sizeof Object2 * NUM_OF_OBJS)); 
// invoke constuctors 
for (size_t i = 0; i < NUM_OF_OBJS; i++) 
    new (&objArray[i]) Object2(/* initializers */); 

// ... do some work 

// invoke destructors 
for (size_t i = 0; i < NUM_OF_OBJS; i++) 
    objArray[i].~Object2(); 

// deallocate memory 
::operator delete (objArray); 
+0

Работает ли static_cast? (Я всегда полагал, что вам нужен reinterpret_cast, чтобы получить от void * к чему-либо еще, но, честно говоря, никогда не пробовал static_cast.) ... и вы забыли уничтожить свои объекты перед удалением массива, вам нужно явно вызвать dtor: для (...) objArray [i]. ~ Object2(); –

+0

+1/more to go/ – osgx

+0

Зачем нам нужен static_cast не простой '(Object2 *)' one? – osgx

0

Если вы действительно нужен массив (непрерывная последовательность объектов) конструктивизируемой типа не по умолчанию, и по некоторым причинам вы cannoy user std::vector (!?), то вам нужно использовать функцию выделения и размещения new.

Это очень трудно сделать надежно; это должно помочь показать, почему. Этот фрагмент включает в себя некоторую защиту от исключений, но более чем вероятно не устойчив ко всем отказам.

const size_t required_count = 100; //e.g. 

// cast to pointer of required type needed for pointer arithmetic 
Object2* objarray = static_cast<Object2*>(operator new(required_count * sizeof(Object2))); 

size_t construction_count = 0; 

try 
{ 
    while (construction_count < required_count) 
    { 
     // params could change with index. 
     new (static_cast<void*>(objarray + construction_count)) Object2(param1, param2); 
     ++construction_count; 
    } 
} 
catch (...) 
{ 
    while (construction_count-- != 0) 
    { 
     try 
     { 
      (&objarray[construction_count])->~Object2(); 
     } 
     catch (...) 
     { 
      // not a lot we can do here, log but don't re-throw. 
     } 
    } 

    operator delete(objarray); 
    throw; 
} 

// Now objarray has been allocated and pointer to an array of required_count Object2 
// It cannot be de-allocated via delete[] or delete; you must loop through 
// calling destructors and then call operator delete on the buffer. 
+1

Существует много веских причин избежать STL, и те, кто избегают STL, также избегают исключений. ;) –

+0

Могу ли я построить объект без размещения new, но используя 'objarray [i] -> Object2 (param1, param2)'? – osgx

+0

@ dash-tom-bang: Я стараюсь быть как можно более нейтральным как можно более нейтральным, только защищаясь от исключений, вызванных сбоем распределения памяти и объекта клиента. Я не бросаю никаких новых исключений, чтобы другие решения не были; они (вообще) просто игнорируют возможные исключения, которых я не знаю. –

Смежные вопросы