Инициализация массива членов в инициализаторе конструктора

99
class C 
{
public:
 C() : arr({1,2,3}) //doesn't compile
{}
    /*
    C() : arr{1,2,3} //doesn't compile either
{}
    */
private:
 int arr[3];
};

Я считаю, что причина в том, что массивы можно инициализировать только с помощью = синтаксиса, а именно:

int arr[3] = {1,3,4};

Вопросы

  1. Как я могу делать то, что хочу (то есть инициализировать массив в конструкторе (не назначая элементы в теле)). Это вообще возможно?
  2. Говорит ли стандарт C ++ 03 что-нибудь особенное об инициализации агрегатов (включая массивы) в инициализаторах ctor? Или недействительность приведенного выше кода является следствием каких-то других правил?
  3. Списки инициализаторов C ++ 0x решают проблему?

PS Прошу не упоминать векторы, boost :: array и их превосходство над массивами, о чем я хорошо осведомлен.

Армен Цирунян
источник
Известно ли вам о существовании массивов фиксированного размера boost, которые предоставляют конструкторы?
Бенуа,
2
@ Бенуа: Я. Но мне нужно знать о простых массивах :)
Армен Цирунян

Ответы:

56
  1. Как я могу делать то, что хочу (то есть инициализировать массив в конструкторе (не назначая элементы в теле)). Это вообще возможно?

Да. Он использует структуру, содержащую массив. Вы говорите, что уже знаете об этом, но тогда я не понимаю вопроса. Таким образом, вы делаете инициализации массива в конструкторе, без назначений в организме. Вот что boost::arrayделает.

Говорит ли стандарт C ++ 03 что-нибудь особенное об инициализации агрегатов (включая массивы) в инициализаторах ctor? Или недействительность приведенного выше кода является следствием каких-то других правил?

Инициализатор памяти использует прямую инициализацию. И правила пункта 8 запрещают подобное. Я не совсем уверен насчет следующего случая, но некоторые компиляторы допускают это.

struct A {
  char foo[6];
  A():foo("hello") { } /* valid? */
};

См. Этот PR GCC для получения дополнительной информации.

Списки инициализаторов C ++ 0x решают проблему?

Да, есть. Однако, я думаю, ваш синтаксис неверен. Вы должны использовать фигурные скобки напрямую, чтобы запустить инициализацию списка

struct A {
  int foo[3];
  A():foo{1, 2, 3} { }
  A():foo({1, 2, 3}) { } /* invalid */
};
Йоханнес Шауб - litb
источник
Я наткнулся на это, когда написал: char * const foo[6];ученик. Требуется, чтобы инициализатор компилировался на C ++ 11.
JATothrim
33

C ++ 98 не предоставляет прямого синтаксиса для чего-либо, кроме обнуления (или для элементов, не относящихся к POD, инициализации значения) массива. Для этого вам просто напишите C(): arr() {}.

Я думаю, что Роджер Пейт ошибается насчет предполагаемых ограничений агрегированной инициализации C ++ 0x, но мне лень искать или проверять, и это не имеет значения, не так ли? РЕДАКТИРОВАТЬ : Роджер говорил о «C ++ 03», я неправильно истолковал его как «C ++ 0x». Извини, Роджер. ☺

Обходной путь C ++ 98 для вашего текущего кода заключается в том, чтобы обернуть массив в a structи инициализировать его статической константой этого типа. В любом случае данные должны где-то находиться. Без манжеты это может выглядеть так:

class C 
{
public:
    C() : arr( arrData ) {}

private:
     struct Arr{ int elem[3]; };
     Arr arr;
     static Arr const arrData;
};

C::Arr const C::arrData = {{1, 2, 3}};
Приветствия и hth. - Альф
источник
Какие ограничения, как я сказал, имеет 0x?
@Roger: «Агрегатная инициализация ... не подходит для инициализатора ctor». Просто проверка C ++ 0x draft N3126, синтаксис mem-initializer , в §12.5.2 / 1, включает использование списка инициализации в фигурных скобках .
Приветствия и hth. - Альф,
6
Первые два слова моего предложения написаны на C ++ 03, ...
8

Обходной путь:

template<class T, size_t N>
struct simple_array { // like std::array in C++0x
   T arr[N];
};


class C : private simple_array<int, 3> 
{
      static simple_array<int, 3> myarr() {
           simple_array<int, 3> arr = {1,2,3};
           return arr;
      }
public:
      C() : simple_array<int, 3>(myarr()) {}
};
Алексей Малистов
источник
3
  1. Нет, к сожалению.
  2. Вы просто не можете так, как хотите, поскольку это не разрешено грамматикой (подробнее ниже). Вы можете использовать только инициализацию, подобную ctor, и, как вы знаете, она недоступна для инициализации каждого элемента в массивах.
  3. Я верю в это, поскольку они универсально распространяют инициализацию многими полезными способами. Но я не уверен в деталях.

В C ++ 03 агрегированная инициализация применяется только с синтаксисом, подобным приведенному ниже, который должен быть отдельным оператором и не подходит для инициализатора ctor.

T var = {...};

источник
2

Как насчет

...
  C() : arr{ {1,2,3} }
{}
...

?

Хорошо компилируется на g ++ 4.8

eold
источник
Это стандарт? Не могли бы вы процитировать соответствующий пункт?
Армен Цирунян
2
Не компилируется на Visual C ++.
сергиол
-3

Вы хотите инициализировать массив целых чисел в своем конструкторе? Направьте его на статический массив.

class C 
{
public:
    int *cArray;

};

C::C {
    static int c_init[]{1,2,3};
    cArray = c_init;
}
DaveEff
источник
2
Это плохая идея, потому что если вы измените этот массив, он изменится для всех экземпляров этого класса.
Morty