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


98
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. Чи говорить С ++ 03 щось особливе про ініціалізацію агрегатів (включаючи масиви) в ініціалізаторах ctor? Або недійсність наведеного вище коду є наслідком деяких інших правил?
  3. Чи вирішують проблему C ++ 0x списки ініціалізаторів?

PS Будь ласка, не зазначайте вектори, boost :: масиви та їх перевагу над масивами, про які я добре знаю.


Вам також відомо про існування посилювальних масивів фіксованого розміру, які надають конструктори?
Беньот

2
@ Benoît: Я. Але мені потрібно знати про звичайні масиви :)
Армен Цирунян

Відповіді:


55
  1. Як я можу робити те, що хочу зробити (тобто ініціалізувати масив у конструкторі (не призначаючи елементи в тілі)). Чи можливо це навіть?

Так. Він використовує структуру, яка містить масив. Ви кажете, що вже знаєте про це, але тоді я не розумію питання. Таким чином, ви робите ініціалізації масиву в конструкторі, без призначень в організмі. Це те, що boost::arrayробить.

Чи говорить С ++ 03 щось особливе про ініціалізацію агрегатів (включаючи масиви) в ініціалізаторах ctor? Або недійсність наведеного вище коду є наслідком деяких інших правил?

Мем-ініціалізатор використовує пряму ініціалізацію. А правила пункту 8 забороняють подібні речі. Я не зовсім впевнений у наступному випадку, але деякі компілятори це дозволяють.

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

Докладніші відомості див. У цьому документі з питань GCC .

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

Так, вони це роблять. Однак ваш синтаксис недійсний, я думаю. Ви повинні використовувати дужки безпосередньо, щоб зняти ініціалізацію списку

struct A {
  int foo[3];
  A():foo{1, 2, 3} { }
  A():foo({1, 2, 3}) { } /* invalid */
};

Я наткнувся на це, коли написав: char * const foo[6];член класу. Він вимагає ініціалізатора для компіляції в C ++ 11.
JATothrim

33

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

У мене річ, що Роджер Пейт помиляється щодо передбачуваних обмежень ініціалізації C ++ 0x, але я занадто ледачий, щоб розглянути його чи перевірити, і це не має значення, чи не так? EDIT : Роджер говорив про "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}};

Які обмеження я сказав 0x?

@Roger: "ініціалізація агрегованого ... не вміщується в ініціалізаторі ctor". Просто перевірка чернетки C ++ 0x N3126, синтаксис мем-ініціалізатора , у п. 12.5.2 / 1, включає використання спискового списку ініційованих записів .
ура та хт. - Альф

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


Це стандарт? Чи можете ви процитувати відповідний пункт, будь ласка?
Армен Цирунян

2
Не компілюється на Visual C ++.
сергіол

-2

Ви хочете запустити масив ints у своєму конструкторі? Наведіть його на статичний масив.

class C 
{
public:
    int *cArray;

};

C::C {
    static int c_init[]{1,2,3};
    cArray = c_init;
}

2
Це погана ідея, тому що якщо змінити цей масив, він зміниться для всіх примірників цього класу.
morty
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.