Я хочу создать на C++ массив объектов без использования STL.C++, массив объектов без <vector>
Как это сделать?
Как я могу создать массив Object2, у которого нет конструктора без аргументов (конструктор по умолчанию)?
Я хочу создать на C++ массив объектов без использования STL.C++, массив объектов без <vector>
Как это сделать?
Как я могу создать массив Object2, у которого нет конструктора без аргументов (конструктор по умолчанию)?
Если тип в вопросе имеет никаких аргументов конструктора, используйте new[]
:
Object2* newArray = new Object2[numberOfObjects];
Не забудьте позвонить delete[]
, когда вам больше не нужен массив:
delete[] newArray;
Если это Безразлично 't использовать такой конструктор operator new
для выделения памяти, затем называть конструкторы на месте:
//do for each object
::new(addressOfObject) Object2(parameters);
Опять же, не забудьте освободить массив, когда он вам больше не нужен.
Object2 не имеет значения по умолчанию c'tor. – kennytm
вы разбили мой мозг этой конструкцией: :: new (address) Object2 (параметры); – Andrey
@ Андрей: Это простое старое размещение нового. – sharptooth
Если конструктор по умолчанию недоступен, вам понадобится массив указателей, а затем цикл над этим массивом для инициализации каждого указателя.
Это вряд ли Быстро: проблемы с распределением и недостатки кэша вероятны. –
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];
}
'Object2 myArray [42];' этот шаг не будет работать, если только у Object2' нет конструктора по умолчанию (объявленного пользователем или иным образом). –
@Charles Bailey. Yup, I заметил, что второй после того, как я разместил его, и изменил его на массив указателей. –
heeey. Это не массив объектов, это массив указателей! – osgx
Очевидный вопрос, почему вы не хотите использовать STL.
Предполагая, что у вас есть причина, вы должны создать массив объектов с чем-то вроде Obj * op = new Obj[4];
. Просто не забудьте избавиться от него delete [] op;
.
Вы не можете сделать это с объектом без конструктора, который не принимает аргументы. В этом случае я думаю, что лучше всего вы можете выделить некоторую память и использовать новое место размещения. Это не так просто, как другие методы.
Я пытаюсь реализовать stl-подобные структуры с нуля. будет не вектором, а smth, как B-дерево векторов постоянной длины, и я хочу полный контроль, поэтому я хочу реализовать его целиком один. – osgx
Используйте массив указателей на 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);
}
Как отмечают другие, это добавляет много накладных расходов на использование памяти (us это куча блоков кучи, каждый из которых стоит кучу кучи) и разбивает пространственную локальность. –
@Ben Voigt, что вы имеете в виду «куча блоков кучи»? Сколько времени занимает куча кучи и требуется ли для каждого нового объекта Object2 (params)? – osgx
Размер заголовка кучи зависит от параметров компилятора и от того, используется ли куча отладки или нет, но для реализаций, с которыми я знаком, это _minimum_ из 2 * sizeof (void *), который составляет 8 байтов для 32- битный процесс. Каждый вызов to :: new, :: new [] или malloc должен содержать пробел для кучи кучи внутри блока кучи, который он возвращает, и обратный адрес почти гарантированно будет кратным sizeof (void *). Было бы необычно, если новый char() фактически выделил бы 64 байта или более в сборке отладки, который имеет проверки для переполнения, переполнения, записи, выполняющей выделение, и т. Д. –
Вы можете делать то, что std::vector
делает и создать блок необработанной памяти. Затем вы создаете свои объекты, которые не имеют конструктора по умолчанию в этой памяти, используя новое место размещения, поскольку они необходимы. Но, конечно, если вы это сделаете, вы могли бы использовать, в первую очередь, std::vector
.
// 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);
Работает ли static_cast? (Я всегда полагал, что вам нужен reinterpret_cast, чтобы получить от void * к чему-либо еще, но, честно говоря, никогда не пробовал static_cast.) ... и вы забыли уничтожить свои объекты перед удалением массива, вам нужно явно вызвать dtor: для (...) objArray [i]. ~ Object2(); –
+1/more to go/ – osgx
Зачем нам нужен static_cast не простой '(Object2 *)' one? – osgx
Если вы действительно нужен массив (непрерывная последовательность объектов) конструктивизируемой типа не по умолчанию, и по некоторым причинам вы 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.
Существует много веских причин избежать STL, и те, кто избегают STL, также избегают исключений. ;) –
Могу ли я построить объект без размещения new, но используя 'objarray [i] -> Object2 (param1, param2)'? – osgx
@ dash-tom-bang: Я стараюсь быть как можно более нейтральным как можно более нейтральным, только защищаясь от исключений, вызванных сбоем распределения памяти и объекта клиента. Я не бросаю никаких новых исключений, чтобы другие решения не были; они (вообще) просто игнорируют возможные исключения, которых я не знаю. –
Из интереса, почему бы вам не использовать stl? – Sean
@osgx: Почему бы просто не определить конструктор по умолчанию? – kennytm
@KennyTM Это нехорошее решение. Многие классы не могут и не должны быть по умолчанию конструктивными. – 2010-03-22 15:32:22