Menginisialisasi array anggota dalam penginisialisasi konstruktor

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];
};

Saya yakin alasannya adalah bahwa array hanya dapat diinisialisasi dengan =sintaks, yaitu:

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

Pertanyaan

  1. Bagaimana saya bisa melakukan apa yang ingin saya lakukan (yaitu, menginisialisasi array dalam konstruktor (tidak menugaskan elemen dalam tubuh)). Apakah itu mungkin?
  2. Apakah standar C ++ 03 mengatakan sesuatu yang khusus tentang menginisialisasi agregat (termasuk array) di penginisialisasi ctor? Atau ketidakabsahan kode di atas adalah akibat wajar dari beberapa aturan lain?
  3. Apakah daftar penginisialisasi C ++ 0x menyelesaikan masalah?

PS Harap tidak menyebutkan vektor, boost :: array, dan keunggulannya terhadap array, yang sangat saya sadari.

Armen Tsirunyan
sumber
Apakah Anda juga mengetahui keberadaan array ukuran tetap boost, yang menyediakan konstruktor?
Benoît
2
@ Benoît: Saya. Tapi saya perlu tahu tentang array biasa :)
Armen Tsirunyan

Jawaban:

55
  1. Bagaimana saya bisa melakukan apa yang ingin saya lakukan (yaitu, menginisialisasi array dalam konstruktor (tidak menugaskan elemen dalam tubuh)). Apakah itu mungkin?

Iya. Ini menggunakan struct yang berisi array. Anda bilang Anda sudah tahu tentang itu, tapi kemudian saya tidak mengerti pertanyaannya. Dengan cara itu, Anda melakukan inisialisasi array di konstruktor, tanpa tugas di badan. Inilah yang boost::arraydilakukannya.

Apakah standar C ++ 03 mengatakan sesuatu yang khusus tentang menginisialisasi agregat (termasuk array) di penginisialisasi ctor? Atau ketidakabsahan kode di atas adalah akibat wajar dari beberapa aturan lain?

Seorang mem-inisialisasi menggunakan inisialisasi langsung. Dan aturan klausul 8 melarang hal semacam ini. Saya tidak begitu yakin tentang kasus berikut, tetapi beberapa kompiler mengizinkannya.

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

Lihat PR GCC ini untuk detail lebih lanjut.

Apakah daftar penginisialisasi C ++ 0x menyelesaikan masalah?

Ya mereka melakukanya. Namun sintaks Anda tidak valid, saya kira. Anda harus menggunakan kawat gigi secara langsung untuk mengaktifkan inisialisasi daftar

struct A {
  int foo[3];
  A():foo{1, 2, 3} { }
  A():foo({1, 2, 3}) { } /* invalid */
};
Johannes Schaub - litb
sumber
Saya menemukan ini ketika saya menulis: char * const foo[6];anggota kelas. Ini membutuhkan penginisialisasi untuk dikompilasi dalam C ++ 11.
JATothrim
33

C ++ 98 tidak menyediakan sintaks langsung untuk apa pun kecuali memusatkan perhatian (atau untuk elemen non-POD, menginisialisasi nilai) larik. Untuk itu Anda hanya menulis C(): arr() {}.

Saya pikir Roger Pate salah tentang dugaan batasan inisialisasi agregat C ++ 0x, tetapi saya terlalu malas untuk mencarinya atau memeriksanya, dan tidak masalah, bukan? EDIT : Roger berbicara tentang "C ++ 03", saya salah membacanya sebagai "C ++ 0x". Maaf, Roger. ☺

Solusi C ++ 98 untuk kode Anda saat ini adalah dengan membungkus array dalam a structdan menginisialisasinya dari konstanta statis jenis itu. Bagaimanapun, data harus berada di suatu tempat. Di luar manset akan terlihat seperti ini:

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}};
Cheers and hth. - Alf
sumber
Batasan apa yang saya katakan 0x miliki?
@Roger: "agrregate inisialisasi ... tidak cocok dengan penginisialisasi ctor". Hanya memeriksa C ++ 0x draft N3126, sintaks dari penginisialisasi-mem , dalam §12.5.2 / 1, termasuk menggunakan daftar braced-init .
Cheers and hth. - Alf
6
Dua kata pertama dari kalimat saya adalah In C ++ 03, ...
8

Solusi:

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()) {}
};
Alexey Malistov
sumber
3
  1. Tidak, sayangnya.
  2. Anda tidak bisa melakukannya dengan cara yang Anda inginkan, karena itu tidak diizinkan oleh tata bahasa (lebih lanjut di bawah). Anda hanya dapat menggunakan inisialisasi mirip ctor, dan, seperti yang Anda ketahui, itu tidak tersedia untuk menginisialisasi setiap item dalam array.
  3. Saya yakin begitu, karena mereka menggeneralisasi inisialisasi di seluruh papan dalam banyak cara yang berguna. Tapi saya tidak yakin dengan detailnya.

Di C ++ 03, inisialisasi agregat hanya berlaku dengan sintaks yang mirip seperti di bawah ini, yang harus berupa pernyataan terpisah dan tidak sesuai dengan penginisialisasi ctor.

T var = {...};

sumber
2

Bagaimana tentang

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

?

Mengompilasi dengan baik pada g ++ 4.8

eold
sumber
Apakah standar ini? Bisakah Anda mengutip klausa yang relevan?
Armen Tsirunyan
2
Tidak dapat dikompilasi pada Visual C ++.
sergiol
-2

Anda ingin memasukkan array int di konstruktor Anda? Arahkan ke array statis.

class C 
{
public:
    int *cArray;

};

C::C {
    static int c_init[]{1,2,3};
    cArray = c_init;
}
DaveEff
sumber
2
Ini ide yang buruk, karena jika Anda mengubah array itu, itu berubah untuk semua instance kelas itu.
morty