Список инициализаторов для динамических массивов? - PullRequest
11 голосов
/ 19 августа 2011

Можно дать список инициализатора для определения статического массива.Пример:

int main()
{
  int int_static[2] = {1,2};
}

Возможен ли подобный список инициализатора для динамического массива?

int main()
{
  int* int_ptr = new int[2];
}

Это ближе к тому, что я пытаюсь сделать:

struct foo
{
  foo(){}
  foo(void * ptr): ptr_(ptr) {}
  void * ptr_;
};

int main()
{
  foo* foo_ptr = new foo[10];
}

Во время инициализации должен вызываться не конструктор по умолчанию, а foo: foo (void *).

Точка наличия статического списка инициализатора для динамического массива может пригодиться в случае Just-In-Время компиляции для ядер акселераторов, у которых имеется только ограниченный объем стека, но в то же время вы создаете свои объекты с помощью статического списка инициализатора (время компиляции акселератора = время выполнения хоста).

Полагаю, нет (поскольку для этого потребуется, чтобы компилятор генерировал дополнительный код, а именно копировал значения аргументов в расположение кучи).Я думаю, что c ++ 0x поддерживает это, но я не могу его использовать.Прямо сейчас я мог бы использовать такую ​​конструкцию.Может быть, кто-то знает хитрость ..

Лучший!

Ответы [ 5 ]

14 голосов
/ 20 июня 2016

В то время, когда ФП опубликовал этот вопрос, поддержка C ++ 11, возможно, еще не была широко распространена, поэтому принятый ответ говорит, что это невозможно. Однако инициализация динамического массива с явным списком инициализаторов теперь должна поддерживаться во всех основных компиляторах C ++.

Синтаксис new int[3] {1, 2, 3} был стандартизирован в C ++ 11. Цитирование страницы new expression на cppreference.com:

Объект, созданный выражением new, инициализируется в соответствии со следующими правилами:
...
Если type является типом массива, массив объектов инициализируется:
...
Если initializer является заключенным в скобки списком аргументов, массив инициализируется агрегатно. (начиная с C ++ 11)

Итак, учитывая пример ОП, при использовании C ++ 11 или новее вполне допустимо следующее:

foo * foo_array = new foo[2] { nullptr, nullptr };

Обратите внимание, что, предоставляя указатели в списке инициализатора, мы фактически уговариваем компилятор применить конструктор foo(void * ptr) (а не конструктор по умолчанию), что было желаемым поведением.

10 голосов
/ 19 августа 2011

Нет, вы не можете этого сделать.

Я думаю, что C ++ не позволяет этого, потому что разрешение такой вещи не добавляет никакой приятной для обладания функции в язык.Другими словами, какой будет смысл динамического массива, если вы используете статический инициализатор для его инициализации?

Смысл динамического массива - создать массивразмером N, который известен во время выполнения, в зависимости от фактической потребности.То есть код

int *p = new int[2]; 

имеет для меня меньшее значение, чем следующий:

int *p = new int[N]; //N is known at runtime

Если это так, то как вы можете указать количество элементов в * 1020?* static инициализатор, потому что N неизвестен до времени выполнения?

Допустим, вам разрешено написать следующее:

int *p = new int[2] {10,20}; //pretend this!

Но какое большое преимущество вы получаетенаписав это?Ничего такого.Его почти такой же, как:

int a[] = {10,20};

Реальным преимуществом будет то, когда вам разрешат писать это для массивов N элементов.Но тогда проблема заключается в следующем:

 int *p = new int[N] {10,20, ... /*Oops, no idea how far we can go? N is not known!*/ };
2 голосов
/ 19 августа 2011

Нет, вам придется создавать элементы динамически.

В качестве альтернативы, вы можете использовать локальный массив и копировать его элементы поверх элементов динамически размещенного массива:

int main() {
   int _detail[] = { 1, 2 };
   int * ptr = new int[2];
   std::copy( _detail, _detail+(sizeof detail / sizeof *detail), ptr );
   delete [] ptr;
}

В ограниченной версии установки всех элементов в 0 вы можете использовать дополнительную пару скобок в вызове new:

int * ptr = new int[2]();  // will value initialize all elements

Но вы, похоже, ищете другое.

0 голосов
/ 19 августа 2011

Учитывая, что ваш реальный класс более сложный, чем int, и построен из разных значений, он сложен.Вектор может быть создан с помощью итераторов, если у вас есть существующий массив / вектор с правильными значениями по умолчанию, или вы должны использовать размещение new.

//vector
int main()
{
  int int_static[2] = {1,2};
  std::vector<int> int_dynamic(int_static, int_static+2);
  //this is what everyone else is saying.  For good reason.
}
//placement new
int function_that_returns_constructed_from_values() {
    return rand();
}
int main() 
{
    int count = 2;
    char *char_dynamic = new char[count * sizeof(int)];
    int *int_dynamic = char_dynamic;
    for(int i=0; i<count; ++i)
        new(int_dynamic+i)int(function_that_returns_constructed_from_values());
    //stuff
    for(int i=0; i<count; ++i)
        (int_dynamic+i)->~int(); //obviously not really int
    delete []char_dynamic;
}

Очевидно, вектор является предпочтительным способомэто.

0 голосов
/ 19 августа 2011

Данные инициализатора должны быть где-нибудь в любом случае. Просто назовите это.

например.,

#include <stddef.h>
#include <algorithm>        // std::copy
#include <vector>

typedef ptrdiff_t   Size;

template< class Type, Size n >
Size countOf( Type (&)[n] ) { return n; }

int main()
{
    using namespace std;

    static int const    initData[]  = {1,2};
    static Size const   n           = countOf( initData );

    // Initialization of a dynamically allocated array:
    int*        pArray  = new int[n];
    copy( initData, initData + n, pArray );

    // Initialization of a vector:
    vector<int> v( initData, initData + n );
}

РЕДАКТИРОВАТЬ : исправлена ​​ошибка в коде выше Я поспешил добавить пример по запросу. Так что я положил ошибочно использовать возвращаемое значение из std::copy.

Приветствия & hth.,

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...