G ++ -Wreorder'ın anlamı nedir?


150

G ++ -Wall seçeneği -Wreorder içerir. Bu seçeneğin ne yaptığı aşağıda açıklanmıştır. Birinin neden umursacağı belli değil (özellikle bunu -Wall'da varsayılan olarak açmak için yeterli).

-Wreorder (yalnızca C ++)
  Kodda verilen üye başlatıcıların sırası olmadığında uyar
  yürütülmesi gereken sırayla eşleşir. Örneğin:

    A yapısı {
      int i;
      int j;
      A (): j (0), i (1) {}
    };

  Derleyici, i ve j için üye başlatıcıları yeniden düzenleyecektir.
  üyelerin beyan düzeniyle eşleşir, buna uyarı gönderir
  etki. Bu uyarı -Wall tarafından etkinleştirilir.

2
Burada bazı iyi cevaplar, ancak kimsenin ilgisini çekmesi durumunda kısa bir kenara: g ++ bunu tam -Werror=reorder
gelişmiş bir

Yanıtlar:


257

Düşünmek:

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

Şimdi ibilinmeyen bir değere sıfırlandı, sıfır değil.

Alternatif olarak, başlatılması i, siparişin önemli olduğu bazı yan etkilere sahip olabilir. Örneğin

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

80
Bu gerçekten belgelerdeki örnek olmalı.
Ben S

3
Teşekkürler. Tiplerimizin çoğu basit başlatıcılara sahip POD tipleri olduğu için bu benim için olmadı. Örneğiniz g ++ manuel örneğinden çok daha iyidir.
Peeter Joot

5
@Mike bunun nedeni derleyicinizin (gcc) başlatılmamış değişkenleri 0 olarak başlatmasıdır, ancak bu bağımlı olmanız gereken bir şey değildir; i 0, başlatılmamış değişkenler için bilinmeyen değerin sadece bir yan etkisidir. 0
ethanwu10

2
@Yakk Sipariş adam sayfası-> ÇOK cevaptı. İşte bu örneği açık bir şekilde listeleyen man sayfasının 2007 tarihli bir arşivi. Ben S'nin yükselen yorumu, birisinin zaten kontrol etmeden bile bir şey olduğunu öneren birinin komik bir örneğidir. web.archive.org/web/20070712184121/http://linux.die.net/man/1/…
KymikoLoco

3
@KymikoLoco Bu sadece yanlış. Man sayfasındaki örnek OP'den (burada iilklendirildiği yer 1) örnektir . Burada, aslında bir sorunu gösteren iolarak başlatılır j.
jazzpi

42

Sorun şu ki, birisi yapıcıdaki üye başlatıcıların listesini görebilir ve bu sırayla yürütüldüklerini düşünebilir (önce j, sonra i). Bunlar, üyelerin sınıfta tanımlandığı sıraya göre yürütülür.

Diyelim ki yazdınız A(): j(0), i(j) {}. Birisi bunu okuyabilir ve ben 0 değeriyle bitirdiğimi düşünebilir. Bu, çünkü başlatılmadığı için ıvır zıvır içeren j ile başlattınız.

Uyarı, yazmanızı hatırlatır A(): i(j), j(0) {}, umarım çok daha balık gibi görünür.


Gerçekten balık gibi görünüyor / kokuyor! :) Kesinlikle kod kokusu :) Bu doğru noktaya açık açıklama için teşekkürler. :)
Will

1
"... size A (): i (j), j (0) {} ..." yazmanızı hatırlatıyor. Bu durumda sınıf üyelerini yeniden sıralamanızı hatırlatırım.
2.718

18

Diğer cevaplar, uyarı seçeneğini haklı çıkaracak bazı iyi örnekler vermiştir. Tarihsel bir bağlam sunacağımı düşündüm. C ++ 'ın yaratıcısı Bjarne Stroustrup, C ++ programlama dili (3. baskı, Sayfa 259) adlı kitabında şöyle açıklıyor :

Üyelerin yapıcıları, kapsayıcı sınıfın kendi yapıcısı yürütülmeden önce çağrılır. Yapıcılar, başlatıcı listesinde göründükleri sırayla değil, sınıfta bildirildikleri sırayla çağrılır. Karışıklığı önlemek için, başlatıcıları bildirim düzeninde belirtmek en iyisidir. Üye yıkıcılar ters sırayla çağrılır.


10

Başlatıcılarınızın yan etkileri varsa bu sizi ısırabilir. Düşünmek:

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

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

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

Yukarıda sezgisel olarak, siparişin başlatıcı listesinde yazıldığı gibi olduğunu varsaysa bile, yukarıdaki "bar" ve ardından "foo" yazdıracaktır.

Alternatif olarak, eğer xvey bir kurucu ile kullanıcı tanımlı bir türdeyse bunlar , bu kurucu aynı belirgin olmayan sonuç ile yan etkilere de sahip olabilir.

Ayrıca bir üye için başlatıcı başka bir üyeye başvurduğunda da kendini gösterebilir.


7

Uyarı, kurucuyu yeni okuduysanız j, daha önce başlatılmış gibi görünüyor i. Biri diğerini başlatmak için kullanılırsa,

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

Sadece kurucuya baktığınızda, bu güvenli görünüyor . Ancak gerçekte, jhenüz başlatma için kullanıldığı noktada henüz başlatılmamıştır ive bu nedenle kod beklendiği gibi çalışmaz. Dolayısıyla uyarı.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.