lakukan {…} sementara (salah)


125

Saya sedang melihat beberapa kode oleh seorang individu dan melihat dia tampaknya memiliki pola dalam fungsinya:

<return-type> function(<params>)
{
 <initialization>

 do
 {
   <main code for function>
 }
 while(false);

 <tidy-up & return>
}

Tidak buruk , lebih aneh (kode sebenarnya cukup rapi dan tidak mengejutkan). Ini bukan sesuatu yang pernah saya lihat sebelumnya dan saya bertanya-tanya apakah ada yang bisa memikirkan logika di baliknya - mungkin latar belakang dalam bahasa yang berbeda?


2
Sudahkah Anda mencoba mengubahnya ke versi "normal" dan melihat apakah masih bisa dikompilasi? Jika gagal untuk dikompilasi saat ditulis secara normal, kesalahan kompilator dapat memberikan petunjuk mengapa hal ini dilakukan.
Mark Byers

11
Mengapa tidak menanyakan "individu" daripada meminta kami untuk menebak niatnya?

1
Mungkin profesornya meminta dia menggunakan a do...while()dan dia telah menggunakan kode itu sebagai template fungsi sejak saat itu.
Hogan

6
@ Neil ... Saya ingin menghindari terlihat bodoh ketika saya menghadapinya dan dia menjelaskan penggunaan C ++ super canggih yang tidak pernah saya pikirkan.
Tn. Boy

6
Sepertinya sudah ada beberapa jawaban yang berbeda, dapatkah Anda bertanya kepada penulis asli apa maksud mereka dan memposting kembali?
nevets1219

Jawaban:


175

Anda bisa breakkeluar dari do{...}while(false).


95
+1 karena mungkin itu maksud dari kode, tetapi melakukan sesuatu seperti ini hanyalah penyamaran yang disamarkan secara idiot. Jika menurut Anda goto adalah alat yang tepat untuk pekerjaan itu, maka Anda sebaiknya menggunakan # $ (* # @ goto.
dsimcha

55
Ini lebih dari sekadar kebodohan terselubung. Ini adalah goto yang dibatasi (terstruktur).
Thomas Eding

19
Dalam hal apa itu "dibatasi"? Hanya melompat ke depan bukanlah "batasan". Sebuah goto adalah sebuah kebagian, dan mendandani satu untuk membuatnya terlihat seperti tidak salah lebih buruk daripada hanya menggunakan kebagian di tempat pertama.
Anon.

44
@Anon .: Melompat ke depan adalah larangan masuk, dan melompat keluar jelas merupakan larangan. Masalah sebenarnya dengan gotos adalah kode spaghetti, dan batas lompatan maju dan keluar yang sangat besar.
David Thornley

33
Sebuah loop yang sebenarnya secara semantik bukanlah sebuah goto. Sebuah kondisional secara semantik bukanlah sebuah goto. "Pergi ke akhir fungsi dan lakukan kode pembersihan" adalah kebagian semantik. Gunakan gotos saat semantik berlaku, jangan mendandani sesuatu yang berbeda secara semantik karena Anda takut padanya.
Anon.

126

Banyak orang mengatakan bahwa istilah ini sering digunakan dengan istirahat sebagai cara canggung untuk menulis "pergi". Itu mungkin benar jika ditulis langsung di fungsinya.

Dalam makro, OTOH, do { something; } while (false)adalah cara mudah untuk MEMAKSA titik koma setelah pemanggilan makro, sama sekali tidak ada token lain yang diizinkan untuk diikuti.

Dan kemungkinan lain adalah bahwa pernah ada loop di sana atau iterasi diantisipasi untuk ditambahkan di masa depan (misalnya dalam pengembangan yang digerakkan oleh pengujian, iterasi tidak diperlukan untuk lulus pengujian, tetapi secara logis masuk akal untuk mengulang di sana jika fungsi harus lebih umum dari yang dibutuhkan saat ini)


18
1 untuk menyebutkan kegunaan ini di makro; Saya terkejut tidak ada orang lain yang menyebutkan itu!
Nick Meyer

7
Ya, hal makro sebenarnya adalah penggunaan yang benar-benar valid dari ini. Tentu saja, makro luar, itu konyol ...;)
jalf

12
Ini tidak canggung, ini berguna, karena ini adalah goto Scoped - itu berarti bahwa variabel apa pun yang Anda deklarasikan di do loop dihancurkan, sedangkan goto tidak melakukan itu.
Ana Betts

9
@Paul: Tidak ada yang mencegah Anda menambahkan tanda kurung di sekitar sekelompok pernyataan untuk memaksa perilaku ini dengan pergi.
erikkallen

5
@Paul: keluar dari blok pasti menyebabkan variabel lokal dihancurkan di C ++, sama seperti istirahat. Dan dalam variabel C tidak benar-benar dihancurkan, ruang tumpukannya diambil kembali.
Ben Voigt

25

Istirahat sebagai goto mungkin adalah jawabannya, tetapi saya akan mengemukakan satu ide lain.

Mungkin dia ingin memiliki variabel yang ditentukan secara lokal dan menggunakan konstruksi ini untuk mendapatkan cakupan baru.

Ingat, meskipun C ++ terbaru memungkinkan untuk di {...}mana saja, hal ini tidak selalu terjadi.


30
Dia bisa saja menggunakan kawat gigi keriting dalam kasus itu.
Nemanja Trifunovic

2
@Nemanja, Anda akan terkejut dengan banyaknya pengembang yang tidak mengetahuinya dan mencoba sesuatu yang berhubungan dengan apa yang disarankan Hogan
Polaris878

8
@Polaris @Nemanja, belum sampai saya memprogram di C / C ++ seperti 4 tahun saya tahu Anda dapat membuat cakupan lokal baru di {} mana saja .. Ini sangat berguna dalam switch-casekode
Earlz

1
@Nemanja: Saya tidak tahu persis kapan, tapi saya yakin di {...}mana saja adalah pengembangan yang lebih modern di C ++ (ingat C ++ pertama yang saya gunakan diimplementasikan dengan pra-prosesor dan itu tidak mengizinkan penggunaan modern ini.) Mungkin penulisnya hanya sekolah lama.
Hogan

2
Kapan tidak memungkinkan adanya kawat gigi di mana-mana? Saya mulai pemrograman seperti 15 tahun yang lalu, dan itu diizinkan (baik di buku teks saya dan di setiap kompiler yang saya coba).
erikkallen

20

Saya telah melihatnya digunakan sebagai pola yang berguna ketika ada banyak titik keluar potensial untuk fungsi tersebut, tetapi kode pembersihan yang sama selalu diperlukan terlepas dari bagaimana fungsi keluar.

Ini bisa membuat pohon if / else-if yang melelahkan jauh lebih mudah dibaca, dengan hanya harus berhenti setiap kali titik keluar tercapai, dengan sisa logika inline sesudahnya.

Pola ini juga berguna dalam bahasa yang tidak memiliki pernyataan goto. Mungkin di situlah programmer asli mempelajari polanya.


15
Kemudian gunakan saja goto yang jujur ​​dan lugas, bukan goto yang disamarkan secara tipis.
dsimcha

4
Saya lebih suka cara ini. Mudah dibaca dan tidak membawa stigma ke mana-mana.
Cameron

8
gotos sangat mudah dibaca jika digunakan dengan hemat dan lokal. Mereka mendapatkan stigma mereka dari belakang ketika mereka menjadi bentuk utama kontrol aliran dan melompati ratusan garis.
dsimcha

13
Tidak menggunakan goto karena "stigma" adalah tanda pasti dari pemrograman kultus kargo.
Anon.

6
Belum lagi bahwa kode pembersihan massal adalah bau busuk. Ini menjadi C ++, kode pembersihan biasanya harus dalam destruktor yang dipanggil selama pemrosesan RAII.
David Thornley

12

Saya telah melihat kode seperti itu sehingga Anda dapat menggunakannya breaksebagai gotosemacam.


10

Ini hanya penyimpangan whileuntuk mendapatkan sematikagoto tidy-up tanpa menggunakan kata goto.

Ini bentuk buruk karena ketika Anda menggunakan lain loop di dalam luar whileyang breaksmenjadi ambigu kepada pembaca. "Apakah ini seharusnya keluar? Atau ini dimaksudkan hanya untuk keluar dari lingkaran dalam?"


10

Saya pikir lebih nyaman untuk menulis breakdaripadagoto end . Anda bahkan tidak perlu memikirkan nama untuk label yang membuat maksudnya lebih jelas: Anda tidak ingin melompat ke label dengan nama tertentu. Anda ingin keluar dari sini.

Juga kemungkinan besar Anda akan membutuhkan kawat gigi. Jadi ini do{...}while(false);versinya:

do {
   // code
   if (condition) break; // or continue
   // more code
} while(false);

Dan inilah cara Anda mengungkapkannya jika Anda ingin menggunakan goto:

{
   // code
   if (condition) goto end;
   // more code
}
end:

Saya pikir arti dari versi pertama jauh lebih mudah untuk dipahami. Juga lebih mudah untuk menulis, lebih mudah untuk diperluas, lebih mudah untuk diterjemahkan ke bahasa yang tidak mendukung goto, dll.


Kekhawatiran yang paling sering disebutkan tentang penggunaan breakadalah penyamarannya yang buruk goto. Tetapi sebenarnya breakmemiliki lebih banyak kemiripan dengan return: Kedua instruksi melompat keluar dari blok kode yang cukup banyak terstruktur dibandingkan dengan goto. Namun demikian kedua instruksi tersebut memungkinkan beberapa titik keluar dalam satu blok kode yang terkadang dapat membingungkan. Bagaimanapun, saya akan mencoba mencari solusi yang paling jelas, apa pun yang ada dalam situasi spesifik.


Oh, saya baru saja menyadari bahwa saya tidak memahami pertanyaan itu sepenuhnya sebelum menjawab. Saya pikir itu tentang penggunaan do{ ... }while(false);secara umum. Tapi sebenarnya ini tentang menggunakannya untuk meniru beberapa jenis try{ ... }finally{ ... }.
Robert

Pengamatan yang bagus tentang kesejajaran antara istirahat dan kembali daripada pergi. Setuju bahwa solusi paling jelas adalah yang terbaik. Dalam banyak kasus, mungkin lebih jelas untuk merangkum kode seperti ini dalam fungsinya sendiri yang terpisah yang menggunakan return daripada break dan kemudian melakukan pembersihan dalam fungsi pemanggil.
persiflage

7

Trik ini digunakan oleh programmer yang terlalu malu untuk menggunakan eksplisit gotodalam kode mereka. Penulis kode di atas ingin memiliki kemampuan untuk melompat langsung ke titik "pembersihan dan pengembalian" dari tengah kode. Namun mereka tidak mau menggunakan label dan eksplisit goto. Sebaliknya, mereka dapat menggunakan bagian breakdalam tubuh dari siklus "palsu" di atas untuk mencapai efek yang sama.


7

Ini adalah praktik yang sangat umum. Dalam C . Saya mencoba memikirkannya seolah-olah Anda ingin membohongi diri sendiri dengan cara "Saya tidak menggunakan goto". Kalau dipikir-pikir, tidak ada salahnya gotomenggunakan kata serupa. Bahkan itu juga akan mengurangi tingkat lekukan.

Meski begitu, saya perhatikan, seringkali do..whileloop ini cenderung tumbuh. Dan kemudian mereka mendapatkan ifs dan elses di dalamnya, membuat kode tersebut sebenarnya tidak terlalu mudah dibaca, apalagi dapat diuji.

Itu do..whilebiasanya dimaksudkan untuk melakukan pembersihan . Dengan segala cara yang memungkinkan, saya lebih suka menggunakan RAII dan kembali lebih awal dari fungsi singkat . Di sisi lain, C tidak memberi Anda kenyamanan sebanyak C ++ , membuat do..whilesalah satu pendekatan terbaik untuk melakukan pembersihan.


6

Sepertinya programmer C. Di C ++, variabel otomatis memiliki destruktor yang Anda gunakan untuk membersihkan, jadi tidak ada yang perlu dirapikan sebelum dikembalikan. Di C, Anda tidak memiliki idiom RAII ini , jadi jika Anda memiliki kode pembersihan yang sama, Anda dapat gotomenggunakannya, atau menggunakan perulangan sekali seperti di atas.

Kerugian utamanya dibandingkan dengan idiom C ++ adalah tidak akan merapikan jika ada pengecualian di tubuh. C tidak memiliki pengecualian, jadi ini bukan masalah, tetapi ini menjadikannya kebiasaan buruk di C ++.


4

Beberapa penjelasan. Yang pertama bersifat umum, yang kedua khusus untuk makro praprosesor C dengan parameter:

Alur kontrol

Saya telah melihat ini digunakan dalam kode C biasa. Pada dasarnya, ini adalah versi goto yang lebih aman, karena Anda dapat keluar darinya dan semua memori dibersihkan dengan benar.

Mengapa sesuatu- gotoseperti itu bagus? Nah, jika Anda memiliki kode di mana hampir setiap baris dapat mengembalikan kesalahan, tetapi Anda perlu bereaksi terhadap semuanya dengan cara yang sama (misalnya dengan menyerahkan kesalahan kepada pemanggil Anda setelah membersihkan), biasanya lebih mudah dibaca untuk menghindari if( error ) { /* cleanup and error string generation and return here */ }as itu menghindari duplikasi kode pembersihan.

Namun, di C ++ Anda memiliki pengecualian + RAII untuk tujuan ini, jadi saya akan menganggapnya gaya pengkodean yang buruk.

Pemeriksaan titik koma

Jika Anda lupa titik koma setelah pemanggilan makro mirip fungsi, argumen mungkin berkontraksi dengan cara yang tidak diinginkan dan dikompilasi menjadi sintaks yang valid. Bayangkan makro

#define PRINT_IF_DEBUGMODE_ON(msg) if( gDebugModeOn ) printf("foo");

Itu secara tidak sengaja disebut sebagai

if( foo )
    PRINT_IF_DEBUGMODE_ON("Hullo\n")
else
    doSomethingElse();

"Lain" akan dianggap terkait dengan gDebugModeOn , jadi bila fooada false, kebalikan dari apa yang dimaksudkan akan terjadi.

Menyediakan ruang lingkup untuk variabel sementara.

Karena do / while memiliki tanda kurung kurawal, variabel sementara memiliki ruang lingkup yang jelas dan tidak dapat mereka hindari.

Menghindari peringatan "titik koma yang mungkin tidak diinginkan"

Beberapa makro hanya diaktifkan di build debug. Anda mendefinisikannya seperti:

#if DEBUG
#define DBG_PRINT_NUM(n) printf("%d\n",n);
#else
#define DBG_PRINT_NUM(n) 
#endif

Sekarang jika Anda menggunakan ini dalam rilis, build di dalam kondisional, itu akan dikompilasi ke

if( foo )
    ;

Banyak kompiler melihat ini sama dengan

if( foo );

Yang sering ditulis secara tidak sengaja. Jadi Anda mendapat peringatan. Do {} while (false) menyembunyikan ini dari kompiler, dan diterima olehnya sebagai indikasi bahwa Anda benar-benar - ingin melakukan apa-apa di sini.

Menghindari pengambilan garis dengan persyaratan

Makro dari contoh sebelumnya:

if( foo )
    DBG_PRINT_NUM(42)
doSomething();

Sekarang, dalam build debug, karena kita juga biasa memasukkan titik koma, kompilasi ini baik-baik saja. Namun, dalam rilis build ini tiba-tiba berubah menjadi:

if( foo )

doSomething();

Atau lebih jelas diformat

if( foo )
    doSomething();

Yang sama sekali bukan yang dimaksudkan. Menambahkan do {...} while (false) di sekitar makro mengubah titik koma yang hilang menjadi kesalahan kompilasi.

Apa artinya bagi OP?

Secara umum, Anda ingin menggunakan pengecualian di C ++ untuk penanganan kesalahan, dan template, bukan makro. Namun, dalam kasus yang sangat jarang terjadi di mana Anda masih memerlukan makro (misalnya saat membuat nama kelas menggunakan penempelan token) atau dibatasi ke C biasa, ini adalah pola yang berguna.


Mengenai pelingkupan, Anda tidak memerlukan perangkat loop; sebuah "polos" blok hukum: x =1; y = 2; { int tmp = y; y = x; x = tmp; }.
chepner

Namun, blok tanpa hiasan tidak memaksakan keberadaan titik koma yang hilang, yang dapat memiliki efek samping yang tidak diinginkan. Lakukan {} saat (); MEMBUTUHKAN titik koma dan dengan demikian misalnya Tidak menyebabkan pernyataan berikut ditarik menjadi "jika" jika makro tidak menentukan apa-apa dalam build rilis, seperti contoh saya di atas.
uliwitness

Tidak bisakah itu dihindari hanya dengan memberikan definisi yang lebih baik untuk makro? #define DBG_PRINT_NUM(n) {}.
chepner

1
Tidak, karena {} adalah pernyataan lengkap, yaitu setara dengan ";". Jadi jika Anda menulis if(a) DBG_PRINT_NUM(n); else other();Ini tidak akan dikompilasi. Hanya if(a) {} else other();atau if(a) ; else other();valid, tetapi if(a) {}; else other();tidak, karena itu membuat klausa "jika" terdiri dari dua pernyataan.
uliwitness

2

Mungkin itu digunakan sehingga breakbisa digunakan di dalam untuk membatalkan eksekusi kode lebih lanjut kapan saja:

do {
    if (!condition1) break;
    some_code;
    if (!condition2) break;
    some_further_code;
    // …
} while(false);

7
Melakukannya sepertinya merupakan upaya untuk menghindari penggunaan gotohanya karena seseorang mendengarnya "buruk".
Anon.

1
Mungkin, tetapi C ++ memiliki pengecualian untuk alasan ini.
TED

2

Saya pikir ini dilakukan untuk menggunakan breakatau continuepernyataan. Semacam logika kode "goto".


2

Sederhana: Tampaknya Anda dapat keluar dari loop palsu kapan saja menggunakan breakpernyataan. Selanjutnya, doblok tersebut adalah ruang lingkup terpisah (yang juga dapat dicapai dengan{ ... } hanya ).

Dalam situasi seperti ini, mungkin ide yang lebih baik untuk menggunakan RAII (objek secara otomatis merusak dengan benar saat fungsi berakhir). Konstruksi serupa lainnya adalah penggunaan goto- ya, saya tahu itu jahat , tetapi dapat digunakan untuk memiliki kode pembersihan umum seperti:

<return-type> function(<params>)
{
 <initialization>

 <main code for function using "goto error;" if something goes wrong>

 <tidy-up in success case & return>

 error:

 <commmon tidy-up actions for error case & return error code or throw exception>
}

(Sebagai tambahan: Konstruksi do-while-false digunakan di Lua untuk memunculkan continuepernyataan yang hilang .)


2

Banyak penjawab memberikan alasannya do{(...)break;}while(false) . Saya ingin melengkapi gambar dengan contoh kehidupan nyata lainnya.

Pada kode berikut saya harus mengatur pencacah operationberdasarkan alamat yang ditunjukkan oleh datapointer. Karena switch-case hanya dapat digunakan pada jenis skalar, saya melakukannya dengan cara yang tidak efisien

if (data == &array[o1])
    operation = O1;
else if (data == &array[o2])
    operation = O2;
else if (data == &array[on])
    operation = ON;

Log("operation:",operation);

Tetapi karena Log () dan kode lainnya diulangi untuk setiap nilai operasi yang dipilih, saya mengembara bagaimana melewatkan sisa perbandingan ketika alamat telah ditemukan. Dan di sinilah do{(...)break;}while(false)berguna.

do {
    if (data == &array[o1]) {
        operation = O1;
        break;
    }
    if (data == &array[o2]) {
        operation = O2;
        break;
    }
    if (data == &array[on]) {
        operation = ON;
        break;
    }
} while (false);

Log("operation:",operation);

Orang mungkin bertanya-tanya mengapa dia tidak bisa melakukan hal yang sama breakdalam sebuah ifpernyataan, seperti:

if (data == &array[o1])
{
    operation = O1;
    break;
}
else if (...)

breakberinteraksi hanya dengan loop atau sakelar terdekat, apakah itu a for, whileatau do .. whiletipe, jadi sayangnya itu tidak akan berhasil.


1

Berapa umur penulisnya?

Saya bertanya karena saya pernah menemukan beberapa kode Fortran real-time yang melakukan itu, di akhir 80-an. Ternyata itu adalah cara yang sangat bagus untuk mensimulasikan utas pada OS yang tidak memilikinya. Anda cukup meletakkan seluruh program (penjadwal Anda) dalam satu putaran, dan memanggil "rangkaian" rutinitas "Anda satu per satu. Rutinitas utas itu sendiri adalah perulangan yang berulang hingga salah satu dari sejumlah kondisi terjadi (seringkali salah satunya adalah sejumlah waktu telah berlalu). Ini adalah "multitasking kooperatif", dalam hal ini tergantung pada masing-masing utas untuk melepaskan CPU sesekali sehingga yang lain tidak kelaparan. Anda dapat menumpuk panggilan subprogram perulangan untuk mensimulasikan prioritas utas band.



0

Saya setuju dengan sebagian besar poster tentang penggunaan sebagai goto yang disamarkan secara tipis. Makro juga telah disebutkan sebagai motivasi potensial untuk menulis kode dalam gaya.

Saya juga telah melihat konstruksi ini digunakan dalam lingkungan C / C ++ campuran sebagai pengecualian orang miskin. The "do {} while (false)" dengan "break" bisa digunakan untuk melompat ke akhir blok kode seandainya sesuatu yang biasanya menjamin pengecualian ditemui di loop.

Saya juga telah menemukan konstruksi ini yang digunakan di toko-toko di mana ideologi "pengembalian tunggal per fungsi" diterapkan. Sekali lagi, ini adalah pengganti dari "goto" yang eksplisit - tetapi motivasinya adalah untuk menghindari beberapa poin kembali, bukan untuk "melewati" kode dan melanjutkan eksekusi aktual dalam fungsi itu.


0

Saya bekerja dengan Adobe InDesign SDK, dan contoh InDesign SDK memiliki hampir semua fungsi yang ditulis seperti ini. Karena faktanya fungsinya biasanya sangat panjang. Di mana Anda perlu melakukan QueryInterface (...) untuk mendapatkan apa pun dari model objek aplikasi. Jadi biasanya setiap QueryInterface diikuti iftidak berjalan dengan baik, break.


0

Banyak yang telah menyatakan kesamaan antara konstruksi ini dan a goto, dan menyatakan preferensi untuk kebagian tersebut. Mungkin latar belakang orang ini termasuk lingkungan di mana goto dilarang keras oleh pedoman pengkodean?


0

Alasan lain yang dapat saya pikirkan adalah karena dekorasi kawat gigi, sedangkan saya percaya kawat gigi telanjang standar C ++ yang lebih baru tidak baik (ISO C tidak menyukainya). Jika tidak, untuk menenangkan penganalisis statis seperti serat.

Tidak yakin mengapa Anda menginginkannya, mungkin cakupan variabel, atau keuntungan dengan debugger.

Lihat Trivial Do While loop , dan Braces is Good dari C2.

Untuk memperjelas terminologi saya (yang menurut saya mengikuti penggunaan standar):

Kawat gigi telanjang :

init();
...
{
c = NULL;
mkwidget(&c);
finishwidget(&c);
}
shutdown();

Kawat gigi kosong (NOP):

{}

misalnya

while (1)
   {}  /* Do nothing, endless loop */

Blokir :

if (finished)
{
     closewindows(&windows);
     freememory(&cache);
}

yang akan menjadi

if (finished)
     closewindows(&windows);
freememory(&cache);

jika kawat gigi dilepas, sehingga mengubah aliran eksekusi, bukan hanya cakupan variabel lokal. Jadi tidak 'berdiri bebas' atau 'telanjang'.

Tanda kurung kurawal atau blok dapat digunakan untuk menandai bagian mana pun dari kode yang mungkin berpotensi untuk fungsi (sebaris) yang ingin Anda tandai, tetapi bukan pemfaktor ulang pada saat itu.


Betulkah? Itu memalukan. Salah satu dari sedikit hal yang saya suka tentang C adalah memungkinkan Anda mendeklarasikan cakupan bersarang baru di mana saja.
TED

1
Kawat gigi telanjang terkadang membantu untuk memperbaiki kerusakan aneh. Lihat blogs.msdn.com/oldnewthing/archive/2004/05/20/135841.aspx .
Brian

1
Dalam C ++, sebuah blok (yaitu "kawat gigi telanjang" Anda) dapat digunakan di mana saja sebuah pernyataan diizinkan.
Ben Voigt

@BenVoigt Empty braces yaitu NOP berbeda dari "kawat gigi telanjang" yang merupakan blok yang ditambahkan di sekitar urutan linier instruksi. Misalnya `printf (" Halo "); {putchar (','); putchar (0x20); } printf ("world! \ n"); `di mana kurung kurawal bukan bagian dari kontrol loop atau cabang.
mctylr

@mctylr: Saya tidak sedang berbicara tentang kawat gigi kosong.
Ben Voigt

0

Ini adalah cara yang dibuat-buat untuk meniru a GOTOkarena keduanya secara praktis identik:

// NOTE: This is discouraged!
do {
    if (someCondition) break;
    // some code be here
} while (false);
// more code be here

dan:

// NOTE: This is discouraged, too!
if (someCondition) goto marker;
// some code be here
marker:
// more code be here

Di sisi lain, keduanya harus benar-benar dilakukan dengan ifs:

if (!someCondition) {
    // some code be here
}
// more code be here

Meskipun penumpukan bisa menjadi sedikit jelek jika Anda hanya mengubah string panjang ke depan GOTOmenjadi ifs bersarang . Jawaban sebenarnya adalah refactoring yang tepat, meskipun, tidak meniru konstruksi bahasa kuno.

Jika Anda mati-matian mencoba mentransliterasi algoritme dengan GOTOs di dalamnya, Anda mungkin bisa melakukannya dengan idiom ini. Ini tentu saja non-standar dan indikator yang baik bahwa Anda tidak mengikuti idiom bahasa yang diharapkan.

Saya tidak mengetahui bahasa seperti C di mana do / while adalah solusi idiomatik untuk apa pun.

Anda mungkin bisa mengubah seluruh kekacauan menjadi sesuatu yang lebih masuk akal untuk membuatnya lebih idiomatis dan lebih mudah dibaca.


1
Alan, do..while(false)adalah tidak untuk menjalankan "terdefinisi" beberapa kali, itu adalah untuk menjalankan sekali .
Dmitry

2
Ini menjalankan beberapa kali jika Anda memiliki continuepernyataan bersyarat di akhir seperti yang saya tunjukkan. Yang undefinedsaya maksudkan adalah Anda tidak tahu apakah ini berjalan lebih dari sekali kecuali Anda dapat memprediksi apakah kondisi akan terpenuhi pada iterasi tertentu. Tanpa continues apa pun di dalamnya, do..while(false)akan berjalan sekali, tetapi juga tanpa breaks di dalamnya, while(true)akan berjalan selamanya, jadi "perilaku default" tidak terlalu relevan untuk memahami apa yang dapat dilakukan dengan loop.
Alan Plum

Ini berguna saat Anda menentukan makro yang memiliki beberapa pernyataan. Jika Anda membungkusnya dalam do / while (false), Anda bisa menggunakan makro dalam pernyataan if / else seperti pemanggilan fungsi lainnya. lihat noveltheory.com/TechPapers/ While.htm untuk penjelasan
John Paquin

5
Seseorang tidak memahami semantik continue. continueTIDAK mengulangi loop. " continuePernyataan itu akan terjadi hanya dalam pernyataan-iterasi dan menyebabkan kontrol untuk lolos ke bagian loop-lanjutan dari pernyataan-iterasi penutup terkecil , yaitu, ke akhir loop."
Ben Voigt

-1, dua pernyataan teratas tidak identik karena alasan yang ditunjukkan @BenVoigt.
cmh

0

Beberapa pembuat kode lebih memilih untuk hanya memiliki satu jalan keluar / kembali dari fungsinya. Penggunaan dummy do {....} while (false); memungkinkan Anda untuk "keluar" dari loop palsu setelah Anda selesai dan masih memiliki satu pengembalian.

Saya seorang pembuat kode java, jadi contoh saya akan seperti ini

import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class p45
{
    static List<String> cakeNames = Arrays.asList("schwarzwald torte", "princess", "icecream");
    static Set<Integer> forbidden = Stream.of(0, 2).collect(Collectors.toSet());

    public static  void main(String[] argv)
    {
        for (int i = 0; i < 4; i++)
        {
            System.out.println(String.format("cake(%d)=\"%s\"", i, describeCake(i)));
        }
    }


    static String describeCake(int typeOfCake)
    {
        String result = "unknown";
        do {
            // ensure type of cake is valid
            if (typeOfCake < 0 || typeOfCake >= cakeNames.size()) break;

            if (forbidden.contains(typeOfCake)) {
                result = "not for you!!";
                break;
            }

            result = cakeNames.get(typeOfCake);
        } while (false);
        return result;
    }
}


-1

Ini lucu. Mungkin ada jeda di dalam loop seperti yang dikatakan orang lain. Saya akan melakukannya dengan cara ini:

while(true)
{
   <main code for function>
   break; // at the end.
}

2
Dengan potensi perulangan selamanya? do..while(false)keluar selalu, while(true)lebih berisiko.
Dmitry

1
while(true)adalah idiom yang benar di sebagian besar bahasa. Anda akan sering menemukannya di aplikasi GUI sebagai loop utama program. Karena Anda pada dasarnya mengasumsikan program tidak boleh mati sampai disuruh melakukannya, do..while(false)akan menyebabkan segala macam logika yang dibuat-buat. Pendekatan ini mungkin lebih bersifat cabul dari sudut pandang perfeksionis, tetapi secara semantik lebih mudah dan dengan demikian lebih sedikit rawan kesalahan bagi pemrogram manusia (maaf, Skynet).
Alan Plum

2
@dmitry do{...}while(false)persis sama denganwhile(true){ .. break;}
N 1,1

4
@ N1.1: Tidak di hadapan continue, mereka tidak sama.
Ben Voigt
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.