Domanda

L'++ -Wall opzione G include -Wreorder. Ciò che questa opzione non è descritto di seguito. Non è ovvio per me perché qualcuno si sarebbe preso cura (abbastanza particolare per attivare questa opzione per impostazione predefinita in -Wall).

-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.
È stato utile?

Soluzione

Si consideri:

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

Ora i è inizializzato a un valore sconosciuto, non zero.

In alternativa, l'inizializzazione di i può avere alcuni effetti collaterali per cui l'ordine è importante. Per es.

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

Altri suggerimenti

Il problema è che qualcuno potrebbe vedere la lista dei inizializzatori membri nel costruttore, e pensare che stanno eseguiti in questo ordine (j, poi i). Essi non sono, essi sono eseguiti nell'ordine i membri sono definite nella classe.

Supponiamo che hai scritto A(): j(0), i(j) {}. Qualcuno potrebbe leggere questo, e pensare che io finisce con il valore 0. Non è così, perché si inizializzato con j, che contiene spazzatura perché non è stato inizializzato per sé.

L'avviso ricorda di scrivere A(): i(j), j(0) {}, che si spera sembra molto più pesce.

Altre risposte hanno fornito alcuni buoni esempi che giustificano l'opzione per un avvertimento. Ho pensato di fornire un certo contesto storico. Il creatore di C ++, Bjarne Stroustrup, spiega nel suo libro Il C ++ linguaggio di programmazione ( 3a edizione, pagina 259):

  

I membri costruttori sono chiamati prima che il corpo della classe contenente viene eseguita proprio costruttore. I costruttori sono chiamati nell'ordine in cui sono dichiarate nella classe piuttosto che l'ordine in cui compaiono nella lista di inizializzazione. Per evitare confusione, è meglio specificare gli inizializzatori in ordine di dichiarazione. I distruttori utente vengono chiamati in ordine inverso di costruzione.

Questo può mordere se i vostri inizializzatori hanno effetti collaterali. Prendere in considerazione:

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

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

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

È possibile che questo stamperà "bar" poi "foo", anche se intuitivamente si potrebbe supporre che l'ordine è, come scritto nella lista di inizializzazione.

In alternativa, se x e y sono di qualche tipo definito dall'utente con un costruttore, tale costruttore può anche avere effetti collaterali, con lo stesso risultato non ovvio.

Si può anche manifestarsi quando inizializzatore per un membro fa riferimento a un altro membro.

Esiste l'avviso perché se hai appena letto il costruttore, sembra j è sempre inizializzata prima i. Questo diventa un problema se uno è utilizzato per inizializzare l'altro, come in

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

Quando si basta guardare il costruttore, questa Look di sicurezza. Ma in realtà, j non è ancora stato inizializzato nel punto in cui viene utilizzato per inizializzare i, e quindi il codice non funzionerà come previsto. Di qui l'avvertimento.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top