Apa "Won't x be leaked"maksudnya Jenis xadalah tipe data bawaan. Mengapa Anda tidak memilih contoh yang lebih baik?
Nawaz
2
@Nawaz: Contoh itu sempurna apa adanya. Hampir setiap kali saya berbicara dengan seseorang goto, mereka berpikir bahwa bahkan variabel durasi penyimpanan otomatis entah bagaimana "bocor". Bahwa Anda dan saya tahu sebaliknya sama sekali tidak penting.
Balapan Ringan di Orbit
1
@ David: Saya setuju bahwa pertanyaan ini jauh lebih masuk akal ketika variabel memiliki destruktor non-sepele ... dan saya melihat jawaban Tomalak dan menemukan contoh seperti itu. Selain itu, meskipun tidak intbisa bocor, bisa juga bocor . Misalnya: void f(void) { new int(5); }kebocoran int.
Ben Voigt
Mengapa tidak mengubah pertanyaan menjadi sesuatu seperti "Dalam contoh yang diberikan, akankah jalur eksekusi kode ditransfer dari f () ke main () tanpa membersihkan stack dan fungsi kembali-dari-fungsi lainnya? Apakah penting jika destruktor diperlukan disebut? Apakah sama di C? " Akankah keduanya mempertahankan maksud pertanyaan, sambil menghindari kemungkinan kesalahpahaman?
Jack V.
Jawaban:
210
Peringatan: Jawaban ini berkaitan dengan C ++ hanya ; aturannya sangat berbeda di C.
Tidak xakan bocor?
Tidak, sama sekali tidak.
Ini adalah mitos yang gotomerupakan beberapa konstruksi tingkat rendah yang memungkinkan Anda untuk mengganti mekanisme pelingkupan bawaan C ++. (Jika ada, itu longjmpmungkin rentan terhadap ini.)
Pertimbangkan mekanisme berikut yang mencegah Anda melakukan "hal buruk" dengan label (yang termasuk case label).
1. Lingkup label
Anda tidak dapat melompati fungsi:
void f(){int x =0;goto lol;}int main(){
f();
lol:return0;}// error: label 'lol' used but not defined
[n3290: 6.1/1]:[..] Ruang lingkup label adalah fungsi di mana label itu muncul. [..]
2. Inisialisasi objek
Anda tidak dapat melompati inisialisasi objek:
int main(){goto lol;int x =0;
lol:return0;}// error: jump to label ‘lol’// error: from here// error: crosses initialization of ‘int x’
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]:[..] Transfer keluar dari loop, keluar dari blok, atau kembali melewati variabel yang diinisialisasi dengan durasi penyimpanan otomatis melibatkan penghancuran objek dengan durasi penyimpanan otomatis yang berada dalam lingkup pada titik yang ditransfer dari tetapi tidak pada titik yang ditransfer ke . [..]
Anda tidak dapat melompat ke dalam cakupan suatu objek, meskipun objek tersebut tidak dijalankan secara eksplisit:
int main(){goto lol;{
std::string x;
lol:
x ="";}}// error: jump to label ‘lol’// error: from here// error: crosses initialization of ‘std::string x’
... kecuali untuk jenis objek tertentu , yang dapat ditangani oleh bahasa karena tidak memerlukan konstruksi "rumit":
int main(){goto lol;{int x;
lol:
x =0;}}// OK
[n3290: 6.7/3]:Dimungkinkan untuk mentransfer ke dalam blok, tetapi tidak dengan cara yang mengabaikan deklarasi dengan inisialisasi. Sebuah program yang melompat dari titik di mana sebuah variabel dengan durasi penyimpanan otomatis tidak dalam cakupan ke titik di mana ia berada dalam ruang lingkup tidak terbentuk kecuali variabel tersebut memiliki tipe skalar, tipe kelas dengan konstruktor standar yang sepele dan destruktor sepele, a versi yang memenuhi syarat cv dari salah satu jenis ini, atau larik dari salah satu jenis sebelumnya dan dideklarasikan tanpa penginisialisasi. [..]
struct T {
T(){ cout <<"*T";}~T(){ cout <<"~T";}};int main(){{
T t;goto lol;}
lol:return0;}// *T~T
[n3290: 6.6/2]:Saat keluar dari ruang lingkup (bagaimanapun tercapai), objek dengan durasi penyimpanan otomatis (3.7.3) yang telah dibangun dalam lingkup itu dihancurkan dalam urutan kebalikan dari konstruksi mereka. [..]
Kesimpulan
Mekanisme di atas memastikan bahwa gotoAnda tidak merusak bahasa.
Tentu saja, ini tidak secara otomatis berarti bahwa Anda "harus" menggunakan gotountuk setiap masalah tertentu, tetapi ini berarti bahwa masalah itu hampir tidak "jahat" seperti yang diyakini oleh mitos umum.
Anda mungkin memperhatikan bahwa C tidak mencegah semua hal berbahaya ini terjadi.
Daniel
13
@Daniel: Pertanyaan dan jawaban sangat spesifik tentang C ++, tapi cukup adil. Mungkin kita bisa mendapatkan FAQ lain untuk menghilangkan mitos bahwa C dan C ++ adalah sama;)
Lightness Races di Orbit
3
@Tomalak: Saya tidak berpikir kami tidak setuju di sini. Banyak dari jawaban yang diberikan pada SO secara eksplisit didokumentasikan di suatu tempat. Saya baru saja menunjukkan bahwa mungkin tergoda bagi programmer C untuk melihat jawaban ini dan berasumsi bahwa jika berfungsi di C ++, ini akan berfungsi serupa di C.
Daniel
2
Anda juga mungkin ingin menambahkan bahwa semua hal yang melompati inisialisasi ini sama untuk label kasus.
PlasmaHH
12
Wow, saya baru saja berasumsi semantik C ++ rusak karena kebagian, tapi ternyata sangat waras! Jawaban yang bagus.
"Won't x be leaked"
maksudnya Jenisx
adalah tipe data bawaan. Mengapa Anda tidak memilih contoh yang lebih baik?goto
, mereka berpikir bahwa bahkan variabel durasi penyimpanan otomatis entah bagaimana "bocor". Bahwa Anda dan saya tahu sebaliknya sama sekali tidak penting.int
bisa bocor, bisa juga bocor . Misalnya:void f(void) { new int(5); }
kebocoranint
.Jawaban:
Peringatan: Jawaban ini berkaitan dengan C ++ hanya ; aturannya sangat berbeda di C.
Tidak, sama sekali tidak.
Ini adalah mitos yang
goto
merupakan beberapa konstruksi tingkat rendah yang memungkinkan Anda untuk mengganti mekanisme pelingkupan bawaan C ++. (Jika ada, itulongjmp
mungkin rentan terhadap ini.)Pertimbangkan mekanisme berikut yang mencegah Anda melakukan "hal buruk" dengan label (yang termasuk
case
label).1. Lingkup label
Anda tidak dapat melompati fungsi:
2. Inisialisasi objek
Anda tidak dapat melompati inisialisasi objek:
Jika Anda melompat kembali melintasi inisialisasi objek, "instance" objek sebelumnya akan dimusnahkan :
Anda tidak dapat melompat ke dalam cakupan suatu objek, meskipun objek tersebut tidak dijalankan secara eksplisit:
... kecuali untuk jenis objek tertentu , yang dapat ditangani oleh bahasa karena tidak memerlukan konstruksi "rumit":
3. Melompat mematuhi ruang lingkup objek lain
Demikian juga, objek dengan durasi penyimpanan otomatis yang tidak "bocor" ketika Anda
goto
keluar dari ruang lingkup mereka :Kesimpulan
Mekanisme di atas memastikan bahwa
goto
Anda tidak merusak bahasa.Tentu saja, ini tidak secara otomatis berarti bahwa Anda "harus" menggunakan
goto
untuk setiap masalah tertentu, tetapi ini berarti bahwa masalah itu hampir tidak "jahat" seperti yang diyakini oleh mitos umum.sumber