2010-09-02 5 views
1

Я хочу создать динамический массив foo, число элементов которого равно x. Аргументы y и z должны быть переданы конструктору элемента foo. Я надеялся, что сделать что-то похожее на:Инициализация динамического массива

Foo* bar = new Foo(y, z)[x]; 

Однако который произвел следующую ошибку компилятора:

error: expected `;' before '[' token 

Так после разговора с опытным другом, он дал мне это, что он признался, был ленивым способ сделать это, но он работает. Мне было интересно, есть ли лучший способ?

Foo* bar = (Foo*) new int[x]; 
for (int i = 0; i < x; i++) { 
    bar[i] = Foo(y, z); 
} 
+6

Вы и ваш друг должны получить [хорошую книгу] (http://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list), чтобы получить хорошую базу понимания. Я имею в виду, что второй блок кода просто ошибочен, зачем выделять 'int', а затем бросать' foo'? Это почти наверняка неопределенное поведение. – GManNickG

ответ

11

«Я хочу, чтобы сделать динамический массив» Так использовать std::vector, она существует по причине.

std::vector<foo> bar(x, foo(y, z)); 

Это создает динамический массив с элементами x инициализируются в foo(y, z).


выше делает копии второго параметра, x раз. Если вы хотите генерировать значения для vector используйте generate_n:

std::vector<double> weights; 
std::generate_n(std::back_inserter(weights), x, ...); 

Вы заменяете ... с функцией или функтором для вызова, который возвращает значение. Как правило, вы делаете функтор:

struct generate_weight 
{ 
    double operator()() const 
    { 
     return random(1e-3); 
    } 
}; 

Giving:

std::generate_n(std::back_inserter(weights), x, generate_weight()); 

Если ваш компилятор поддерживает C++ 0x, вы можете воспользоваться лямбда-х. Они делают то же самое, за исключением того, что исходный код кратким и локализуется:

std::generate_n(std::back_inserter(weights), x, 
       [](){ return random(1e-3); }); 
+0

Несмотря на то, что это хорошо работает, в этом примере он возвращает одинаковое число для всех элементов массива: std :: vector вес (х, случайный (1е-3)); – dcousens

+0

@ Daniel: В самом деле, он инициализирует его 'x' копиями' foo (y, z) '. В твоем вопросе ничего не говорилось; задайте реальные вопросы, чтобы получить реальные ответы. Я обновил свой ответ. – GManNickG

+0

Я просто смотрел, было ли это ожидаемое поведение, не имея опыта работы с STL до этого. В качестве примера я использовал случайный (1е-3). Спасибо за расширенный ответ. – dcousens

1

Если вы хотите, чтобы инициализировать каждый элемент на ту же величину, то делать, как предложено GMan выше:

std::vector<foo> bar(x, foo(y, z)); 

Вы будете имеют вектор X элементов, каждый из которых имеет одинаковые foo (y, z);

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

std::vector<foo> bar; 

    for (int i = 0; i < x; ++i) 
    { 
     // initialize X foos with different values for each foo. 
     bar.push_back(foo(i, random(i))); 
    } 
0

Если вы настаиваете на том, чтобы не использовать std, по крайней мере, сделать это правильно. Это небезопасно и имеет проблемы с BIG.

size_t x = 10; 
foo * bar= static_cast<foo*> (::operator new (sizeof(foo)* x)); 
for (size_t i=0; i<x; ++i) 
{ 
    new (&bar[i]) foo (1,1); 
} 

::operator delete (bar); 
+1

Здесь нет проблем с выравниванием, 'operator new' возвращает максимально выровненный блок памяти. – GManNickG

+0

@GMan - Боюсь, что это не будет игнорировать выравнивание foo. –

+1

Опять же, нет проблем с выравниванием. §3.7.3.1/2: «... Возвращенный указатель должен быть соответствующим образом выровнен, чтобы его можно было преобразовать в указатель любого полного типа объекта, а затем использовать для доступа к объекту или массиву в выделенном хранилище ...» – GManNickG

1

Во-первых, только инициализатор вы можете использовать в массиве новых выражений является (). Итак, это вы только варианты, если вы хотите использовать новое выражение-

foo *bar = new foo[x]; // 1. no initializer 
foo *bar = new foo[x](); // 2. `()` initializer 

В зависимости от того, как foo определяется, эти два могут вести себя одинаково или по-разному.

Во-вторых, поскольку вы не можете передать аргументы конструктора (y,z) в новое выражение, вы должны по умолчанию построить свой массив (как показано выше), а затем использовать назначение, чтобы дать вашим элементам массива конкретные значения. Для этого ваш foo должен быть по умолчанию и может быть назначен для копирования. Код будет выглядеть примерно так, как предполагал ваш «опытный друг», но с соответствующими типами (вместо int). То, что у вас сейчас, бесполезно (откуда вышло int?). Скорее всего, вы неправильно поняли своего опытного друга. Вот как это должно выглядеть

foo *bar = new foo[x]; 
for (int i = 0; i < x; i++) 
    bar[i] = foo(y,z); 

В-третьих, в вашем конкретном случае std::vector будет делать то же самое в гораздо более изящным способом.

+0

Это был мой исходный код, однако мне пришлось бы сделать конструктор без аргументов (как вы сказали, «по умолчанию конструктив»?) При использовании «foo * bar = new foo [x];». И затем повторите их все, как вы это сделали. – dcousens

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