Frage

Die g ++ -Wall Option beinhaltet -Wreorder. Was diese Option tut, ist unten beschrieben. Es ist mir nicht klar, warum jemand kümmern würde (vor allem genug, um dies in -Wall standardmäßig eingeschaltet).

-Wreorder (C++ only)
  Warn when the order of member initializers given in the code does not
  match the order in which they must be executed.  For instance:

    struct A {
      int i;
      int j;
      A(): j (0), i (1) { }
    };

  The compiler will rearrange the member initializers for i and j to
  match the declaration order of the members, emit-ting a warning to that
  effect.  This warning is enabled by -Wall.
War es hilfreich?

Lösung

Bedenken Sie:

struct A {
    int i;
    int j;
    A() : j(0), i(j) { }
};

Jetzt i an einen unbekannten Wert initialisiert wird, nicht Null ist.

Alternativ kann die Initialisierung von i einige Nebenwirkungen haben, für die die Reihenfolge wichtig ist. Z.

A(int n) : j(n++), i(n++) { }

Andere Tipps

Das Problem ist, dass jemand könnte die Liste des Mitglied initialisers im Konstruktor sehen, und denkt, dass sie in dieser Reihenfolge ausgeführt sind (j zuerst, dann i). Sie sind nicht, sie in der Reihenfolge ausgeführt, werden die Elemente in der Klasse definiert sind.

Angenommen, Sie schrieb A(): j(0), i(j) {}. Jemand könnte, dass lesen, und denkt, dass ich mit dem Wert ende 0. Es ist nicht, weil Sie es mit j initialisiert, der Junk enthält, weil sie nicht selbst initialisiert.

Die Warnung erinnert Sie A(): i(j), j(0) {} zu schreiben, die hoffentlich noch viel mehr faul aussieht.

Andere Antworten haben einige gute Beispiele zur Verfügung gestellt, die die Option für eine Warnung rechtfertigen. Ich dachte, ich einigen historischen Kontext bieten würde. Der Schöpfer von C ++, Bjarne Stroustrup, erklärt in seinem Buch Die C ++ Programmiersprache ( 3. Auflage, Seite 259):

  

Der Mitgliederbauer genannt werden, bevor der Körper der umschließenden Klasse eigenen Konstruktor ausgeführt wird. Die Konstrukteure sind in der Reihenfolge aufgerufen, in der sie in der Klasse deklariert sind und nicht die Reihenfolge, in der sie in der Initialisierungsliste erscheinen. Um Verwirrung zu vermeiden, ist es am besten, die Initialisierungen in der Reihenfolge der Deklaration angeben. Das Mitglied Destruktoren wird in umgekehrter Reihenfolge der Konstruktion genannt.

Das kann dich beißen, wenn Ihr initializers Nebenwirkungen haben. Bedenken Sie:

int foo() {
    puts("foo");
    return 1;
}

int bar() {
    puts("bar");
    return 2;
}

struct baz {
    int x, y;
    baz() : y(foo()), x(bar()) {}
};

Das oben gedruckt wird „bar“ und dann „foo“, obwohl intuitiv annehmen würde man, dass Reihenfolge wie in der Initialisiererliste geschrieben ist.

Wenn alternativ x und y einigen benutzerdefinierten Typ mit einem Konstruktor ist, kann dieser Konstruktor auch Nebenwirkungen haben, mit dem gleichen nicht-offensichtlichen Ergebnis.

Es kann auch selbst manifestieren, wenn Initialisierer für ein Mitglied ein anderes Mitglied verweist.

Die Warnung besteht, weil, wenn Sie nur den Konstruktor lesen, es sieht aus wie j vor i initialisiert zu werden. Dies wird zu einem Problem, wenn man verwendet wird, um die andere, wie in

zu initialisieren
struct A {
  int i;
  int j;
  A(): j (0), i (this->j) { }
};

Wenn Sie nur an den Konstruktor suchen, diese sieht sicher. Aber in Wirklichkeit hat j noch nicht an dem Punkt initialisiert, wo es verwendet wird i zu initialisieren, und so wird der Code nicht wie erwartet funktionieren. Daher die Warnung.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top