Initialisieren eines Member-Arrays im Konstruktor-Initialisierer

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

Ich glaube, der Grund dafür ist, dass Arrays nur mit =Syntax initialisiert werden können, dh :

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

Fragen

  1. Wie kann ich tun, was ich tun möchte ( dh ein Array in einem Konstruktor initialisieren (keine Elemente im Body zuweisen)). Ist es überhaupt möglich?
  2. Sagt der C ++ 03-Standard etwas Besonderes über die Initialisierung von Aggregaten (einschließlich Arrays) in CTOR-Initialisierern? Oder ist die Ungültigkeit des obigen Codes eine Folge einiger anderer Regeln?
  3. Lösen C ++ 0x-Initialisiererlisten das Problem?

PS Bitte erwähnen Sie keine Vektoren, Boost :: Arrays und deren Überlegenheit gegenüber Arrays, die mir bekannt sind.

Armen Tsirunyan
quelle
Ist Ihnen auch die Existenz von Boost-Arrays mit fester Größe bekannt, die Konstruktoren bereitstellen?
Benoît
2
@ Benoît: Das bin ich. Aber ich muss über einfache Arrays Bescheid wissen :)
Armen Tsirunyan

Antworten:

55
  1. Wie kann ich tun, was ich tun möchte (dh ein Array in einem Konstruktor initialisieren (keine Elemente im Body zuweisen)). Ist es überhaupt möglich?

Ja. Es wird eine Struktur verwendet, die ein Array enthält. Sie sagen, Sie wissen das bereits, aber dann verstehe ich die Frage nicht. Auf diese Weise Sie tun ein Array im Konstruktor initialisieren, ohne Zuweisungen im Körper. Das boost::arraymacht es.

Sagt der C ++ 03-Standard etwas Besonderes über die Initialisierung von Aggregaten (einschließlich Arrays) in CTOR-Initialisierern? Oder ist die Ungültigkeit des obigen Codes eine Folge einiger anderer Regeln?

Ein Mem-Initialisierer verwendet die direkte Initialisierung. Und die Regeln von Klausel 8 verbieten so etwas. Ich bin mir über den folgenden Fall nicht ganz sicher, aber einige Compiler erlauben dies.

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

Weitere Informationen finden Sie in dieser GCC PR .

Lösen C ++ 0x-Initialisiererlisten das Problem?

Ja, das tun sie. Ihre Syntax ist jedoch ungültig, denke ich. Sie müssen Klammern direkt verwenden, um die Listeninitialisierung auszulösen

struct A {
  int foo[3];
  A():foo{1, 2, 3} { }
  A():foo({1, 2, 3}) { } /* invalid */
};
Johannes Schaub - litb
quelle
Ich bin darauf gestoßen, als ich schrieb: char * const foo[6];Klassenmitglied. Es erfordert die Initialisierung in C ++ 11 zu kompilieren.
JATothrim
32

C ++ 98 bietet keine direkte Syntax für etwas anderes als das Nullstellen (oder für Nicht-POD-Elemente, Wertinitialisierung) des Arrays. Dafür schreibst du einfach C(): arr() {}.

Ich denke, Roger Pate ist falsch in Bezug auf die angeblichen Einschränkungen der C ++ 0x-Aggregatinitialisierung, aber ich bin zu faul, um sie nachzuschlagen oder zu überprüfen, und es spielt keine Rolle, oder? EDIT : Roger hat über "C ++ 03" gesprochen, ich habe es als "C ++ 0x" falsch verstanden. Entschuldigung, Roger. ☺

Eine C ++ 98-Problemumgehung für Ihren aktuellen Code besteht darin, das Array in a zu verpacken structund es anhand einer statischen Konstante dieses Typs zu initialisieren. Die Daten müssen sich sowieso irgendwo befinden. Aus der Manschette kann es so aussehen:

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}};
Prost und hth. - Alf
quelle
Welche Einschränkungen habe ich 0x gesagt?
@ Roger: "Agrregate-Initialisierung ... passt nicht in einen Ctor-Initialisierer". Nur die Überprüfung des C ++ 0x-Entwurfs N3126, die Syntax eines Mem-Initialisierers in §12.5.2 / 1, beinhaltet die Verwendung einer geschweiften Init-Liste .
Prost und hth. - Alf
6
Die ersten beiden Wörter meines Satzes sind In C ++ 03, ...
8

Problemumgehung:

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
quelle
3
  1. Leider nein.
  2. Sie können einfach nicht so, wie Sie es möchten, da dies in der Grammatik nicht zulässig ist (mehr unten). Sie können nur eine ctor-ähnliche Initialisierung verwenden. Wie Sie wissen, ist diese Option nicht für die Initialisierung der einzelnen Elemente in Arrays verfügbar.
  3. Ich glaube schon, da sie die Initialisierung auf viele nützliche Arten verallgemeinern. Bei den Details bin ich mir aber nicht sicher.

In C ++ 03 gilt die aggregierte Initialisierung nur mit einer Syntax wie der folgenden. Diese muss eine separate Anweisung sein und passt nicht in einen ctor-Initialisierer.

T var = {...};

quelle
2

Wie wäre es mit

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

?

Kompiliert gut auf g ++ 4.8

eold
quelle
Ist das Standard? Können Sie bitte die entsprechende Klausel zitieren?
Armen Tsirunyan
2
Kompiliert nicht unter Visual C ++.
Sergiol
-2

Sie möchten ein Array von Ints in Ihrem Konstruktor initiieren? Zeigen Sie auf ein statisches Array.

class C 
{
public:
    int *cArray;

};

C::C {
    static int c_init[]{1,2,3};
    cArray = c_init;
}
DaveEff
quelle
2
Dies ist eine schlechte Idee, denn wenn Sie dieses Array ändern, wird es für alle Instanzen dieser Klasse geändert.
Morty