Goto sızıntı değişkenleri kullanılacak mı?


94

gotoYıkıcıları ve nesneleri çağırmadan kod parçalarının üzerinden atladığı doğru mu?

Örneğin

void f() {
   int x = 0;
   goto lol;
}

int main() {
   f();
lol:
   return 0;
}

Olmaz xsızdırılmış olabilir?


İlgili: stackoverflow.com/questions/1258201/… (ama bunu sıfırdan, temiz bir şekilde yapmak istedim!)
Orbit

15
Ne anlama "Won't x be leaked"geliyor? Türü, xyerleşik bir veri türüdür. Neden daha iyi bir örnek seçmiyorsun?
Nawaz

2
@Nawaz: Örnek olduğu haliyle mükemmel. Neredeyse biriyle hakkında her konuştuğumda goto, otomatik depolama süresi değişkenlerinin bile bir şekilde "sızdırıldığını" düşünüyorlar. Senin ve benim bunun aksini bildiğimiz, tamamen konunun dışında.
Orbit'te Hafiflik Yarışları

1
@David: Değişken önemsiz olmayan bir yıkıcıya sahip olduğunda bu sorunun çok daha mantıklı olduğuna katılıyorum ... ve Tomalak'ın cevabına baktım ve böyle bir örnek buldum. Bir süre Dahası, intsızıntı edemez, bu olabilir sızdırılmış olması . Örneğin: void f(void) { new int(5); }bir int.
Ben Voigt

Neden soruyu "Verilen örnekte, kod yürütme yolu, yığını ve diğer işlevden dönüş işlevlerini temizlemeden f () 'den main ()' e aktarılacak mı? deniyor mu? C de aynı mı? " Her ikisi de olası yanlış anlamalardan kaçınırken sorunun amacını da koruyacak mı?
Jack V.

Yanıtlar:


210

Uyarı: Bu yanıt yalnızca C ++ ile ilgilidir ; C'de kurallar oldukça farklı.


Olmaz xsızdırılmış olabilir?

Kesinlikle değil.

gotoC ++ 'ın yerleşik kapsam mekanizmalarını geçersiz kılmanıza izin veren bazı düşük seviyeli yapılar olan bir efsanedir . (Bir şey varsa, buna longjmpeğilimli olabilir.)

Etiketlerle ( caseetiketler dahil) "kötü şeyler" yapmanızı önleyen aşağıdaki mekanizmaları düşünün .


1. Etiket kapsamı

İşlevler arasında geçiş yapamazsınız:

void f() {
   int x = 0;
   goto lol;
}

int main() {
   f();
lol:
   return 0;
}

// error: label 'lol' used but not defined

[n3290: 6.1/1]:[..] Bir etiketin kapsamı, içinde göründüğü işlevdir. [..]


2. Nesne başlatma

Nesne ilklendirmesine atlayamazsınız:

int main() {
   goto lol;
   int x = 0;
lol:
   return 0;
}

// error: jump to label ‘lol’
// error:   from here
// error:   crosses initialization of ‘int x’

Atlarsan geri nesne başlatma karşısında, daha sonra nesnenin önceki "örneği" yok edilir :

struct T {
   T() { cout << "*T"; }
  ~T() { cout << "~T"; }
};

int main() {
   int x = 0;

  lol:
   T t;
   if (x++ < 5)
     goto lol;
}

// Output: *T~T*T~T*T~T*T~T*T~T*T~T

[n3290: 6.6/2]:[..] Bir döngüden, bir bloktan veya otomatik depolama süresi ile başlatılmış bir değişkeni geri geçerek transfer, transfer edilen ancak transfer edilen noktada olmayan noktada kapsam içinde olan otomatik depolama süresi olan nesnelerin yok edilmesini içerir . [..]

Açıkça başlatılmamış olsa bile bir nesnenin kapsamına atlayamazsınız:

int main() {
   goto lol;
   {
      std::string x;
lol:
      x = "";
   }
}

// error: jump to label ‘lol’
// error:   from here
// error:   crosses initialization of ‘std::string x’

... "karmaşık" yapı gerektirmedikleri için dilin üstesinden gelebileceği belirli nesne türleri dışında

int main() {
   goto lol;
   {
      int x;
lol:
      x = 0;
   }
}

// OK

[n3290: 6.7/3]:Bir bloğa transfer etmek mümkündür, ancak başlatma ile bildirimleri atlayacak şekilde değil. Otomatik depolama süresi olan bir değişkenin kapsam içinde olmadığı bir noktadan, değişken skaler tip, önemsiz bir varsayılan kurucuya sahip sınıf tipi ve önemsiz bir yıkıcıya sahip olmadığı sürece kötü biçimlendirilmiş bir noktaya sıçrayan bir program, a Bu türlerden birinin cv nitelikli sürümü veya önceki türlerden birinin dizisi ve bir başlatıcı olmadan bildirilir. [..]


3. Atlama diğer nesnelerin kapsamına göre değişir

Aynı şekilde, otomatik depolama süresi nesneler vardır değil "sızan" sizi gotodışarı onların kapsamı :

struct T {
   T() { cout << "*T"; }
  ~T() { cout << "~T"; }
};

int main() {
   {
      T t;
      goto lol;
   }

lol:
   return 0;
}

// *T~T

[n3290: 6.6/2]:Bir kapsamdan çıkıldığında (ne kadar başarılı olursa olsun), o kapsamda inşa edilen otomatik depolama süresine (3.7.3) sahip nesneler, yapımlarının tersi sırada imha edilir. [..]


Sonuç

Yukarıdaki mekanizmalar gotobunun dili kırmanıza izin vermemesini sağlar.

Tabii ki, bu otomatik olarak anlamına gelmez sen kullanımı "gereken" gotoHerhangi bir sorunun, ancak does neredeyse inanmak ortak efsane açar insanlar olarak "kötü" olarak olmadığını ortalama.


8
C'nin tüm bu tehlikeli şeylerin olmasını engellemediğini fark edebilirsiniz.
Daniel

13
@Daniel: Soru ve cevap çok özel olarak C ++ ile ilgili, ancak doğru nokta. Belki de C ve C ++ 'nın aynı olduğu efsanesini ortadan kaldıran başka bir SSS alabiliriz;)
Orbit

3
@Tomalak: Burada aynı fikirde olmadığımızı sanmıyorum. SO'da verilen cevapların çoğu bir yerlerde açıkça belgelenmiştir. Sadece bu cevabı bakın ve C çalışırsa ++, bu C. Benzer çalışması gerektiğini varsaymak bir C programcısı cazip olabileceği noktayı çıkıyordu
Daniel

2
Ayrıca, tüm bu ilkleştirme atlamalarının vaka etiketleri için aynı olduğunu eklemek isteyebilirsiniz.
PlasmaHH

12
Vay canına, C ++ 'ın anlambiliminin gitmek için bozuk olduğunu varsaymıştım, ama şaşırtıcı bir şekilde mantıklılar! Mükemmel cevap.
Joseph Garvin
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.