Ketika melakukan review kode untuk seorang rekan hari ini saya melihat hal yang aneh. Dia telah mengelilingi kode barunya dengan kurung kurawal seperti ini:
Constructor::Constructor()
{
existing code
{
New code: do some new fancy stuff here
}
existing code
}
Apa hasilnya, jika ada, dari ini? Apa yang bisa menjadi alasan untuk melakukan ini? Dari mana kebiasaan ini berasal?
Edit:
Berdasarkan input dan beberapa pertanyaan di bawah ini saya merasa bahwa saya harus menambahkan beberapa ke pertanyaan, meskipun saya sudah menandai jawaban.
Lingkungan adalah perangkat yang disematkan. Ada banyak kode warisan C yang dibungkus pakaian C ++. Ada banyak C yang berubah menjadi pengembang C ++.
Tidak ada bagian penting dalam bagian kode ini. Saya hanya melihatnya di bagian kode ini. Tidak ada alokasi memori utama yang dilakukan, hanya beberapa flag yang disetel, dan beberapa twiddling.
Kode yang dikelilingi oleh kurung kurawal adalah sesuatu seperti:
{
bool isInit;
(void)isStillInInitMode(&isInit);
if (isInit) {
return isInit;
}
}
(Jangan pedulikan kodenya, cukup tempelkan ke kurung kurawal ...;)) Setelah kurung kurawal ada beberapa yang lebih mengutak-atik, memeriksa keadaan, dan pensinyalan dasar.
Saya berbicara dengan pria itu dan motivasinya adalah untuk membatasi ruang lingkup variabel, penamaan bentrokan, dan beberapa lainnya yang saya tidak bisa mengerti.
Dari POV saya ini tampaknya agak aneh dan saya tidak berpikir bahwa kurung kurawal harus ada dalam kode kita. Saya melihat beberapa contoh bagus di semua jawaban tentang mengapa seseorang bisa mengelilingi kode dengan kurung kurawal, tetapi bukankah seharusnya Anda memisahkan kode menjadi metode?
sumber
Jawaban:
Kadang-kadang bagus karena memberi Anda ruang lingkup baru, di mana Anda dapat lebih "bersih" mendeklarasikan variabel baru (otomatis).
Dalam
C++
hal ini mungkin tidak begitu penting karena Anda dapat memperkenalkan variabel baru di mana saja, tetapi mungkin kebiasaan itu berasalC
, di mana Anda tidak dapat melakukan ini sampai C99. :)Karena
C++
memiliki destruktor, juga berguna untuk memiliki sumber daya (file, mutex, apa pun) yang secara otomatis dirilis ketika ruang lingkup keluar, yang dapat membuat semuanya lebih bersih. Ini berarti Anda dapat bertahan pada beberapa sumber daya bersama untuk durasi yang lebih pendek daripada yang Anda lakukan jika Anda mengambilnya di awal metode.sumber
Salah satu tujuan yang mungkin adalah untuk mengontrol ruang lingkup variabel . Dan karena variabel dengan penyimpanan otomatis dihancurkan ketika mereka keluar dari ruang lingkup, ini juga dapat memungkinkan destruktor disebut lebih awal daripada yang seharusnya.
sumber
for
pernyataan saya untuk membuat berumur pendekint i;
di C89. Tentunya Anda tidak menyarankan bahwa setiap orangfor
harus berada dalam fungsi yang terpisah?Kawat gigi tambahan digunakan untuk menentukan ruang lingkup variabel yang dideklarasikan di dalam kawat gigi. Hal ini dilakukan agar destruktor akan dipanggil ketika variabel keluar dari ruang lingkup. Di destruktor, Anda dapat merilis mutex (atau sumber daya lainnya) sehingga orang lain bisa mendapatkannya.
Dalam kode produksi saya, saya telah menulis sesuatu seperti ini:
Seperti yang Anda lihat, dengan cara ini, Anda dapat menggunakan
scoped_lock
dalam suatu fungsi dan pada saat yang sama, dapat menentukan cakupannya dengan menggunakan kawat gigi tambahan. Ini memastikan bahwa meskipun kode di luar kawat gigi tambahan dapat dieksekusi oleh beberapa utas secara bersamaan, kode di dalam kawat gigi akan dieksekusi dengan tepat satu utas pada satu waktu.sumber
scoped_lock
yang akan dihancurkan pada pengecualian. Saya biasanya lebih suka memperkenalkan ruang lingkup baru untuk kunci juga, tetapi dalam beberapa kasusunlock
ini sangat berguna. Misalnya untuk mendeklarasikan variabel lokal baru di dalam bagian kritis dan kemudian menggunakannya nanti. (Saya tahu saya terlambat, tetapi hanya untuk kelengkapan ...)Seperti yang telah ditunjukkan orang lain, blok baru memperkenalkan ruang lingkup baru, memungkinkan seseorang untuk menulis sedikit kode dengan variabel sendiri yang tidak membuang namespace dari kode sekitarnya, dan tidak menggunakan sumber daya lebih lama dari yang diperlukan.
Namun, ada alasan bagus lain untuk melakukan ini.
Ini hanya untuk mengisolasi blok kode yang mencapai tujuan (sub) tertentu. Jarang pernyataan tunggal mencapai efek komputasi yang saya inginkan; biasanya dibutuhkan beberapa. Menempatkan mereka di blok (dengan komentar) memungkinkan saya memberi tahu pembaca (seringkali saya sendiri di kemudian hari):
misalnya
Anda mungkin berpendapat saya harus menulis fungsi untuk melakukan semua itu. Jika saya hanya melakukannya sekali, menulis fungsi hanya menambah sintaks dan parameter tambahan; sepertinya tidak ada gunanya. Anggap saja ini sebagai fungsi anonim tanpa parameter.
Jika Anda beruntung, editor Anda akan memiliki fungsi lipatan / buka yang bahkan akan membiarkan Anda menyembunyikan blokir.
Saya melakukan ini sepanjang waktu. Sangat menyenangkan mengetahui batas-batas kode yang perlu saya periksa, dan bahkan lebih baik untuk mengetahui bahwa jika potongan itu bukan yang saya inginkan, saya tidak harus melihat salah satu baris.
sumber
Salah satu alasannya adalah bahwa masa pakai variabel yang dideklarasikan di dalam blok kurung kurawal baru terbatas pada blok ini. Alasan lain yang terlintas dalam pikiran adalah untuk dapat menggunakan kode lipat di editor favorit.
sumber
Ini sama dengan blok
if
(atauwhile
dll.), Hanya tanpaif
. Dengan kata lain, Anda memperkenalkan ruang lingkup tanpa memperkenalkan struktur kontrol."Pelingkupan eksplisit" ini biasanya berguna dalam kasus-kasus berikut:
using
.Contoh 1:
Jika
my_variable
terjadi menjadi sangat baik nama untuk dua variabel yang berbeda yang digunakan dalam isolasi dari satu sama lain, maka scoping eksplisit memungkinkan Anda untuk menghindari menciptakan nama baru hanya untuk menghindari nama bentrokan.Ini juga memungkinkan Anda untuk menghindari penggunaan di
my_variable
luar ruang lingkup yang dimaksudkan secara tidak sengaja.Contoh 2:
Situasi praktis saat ini bermanfaat jarang terjadi dan dapat mengindikasikan bahwa kode tersebut sudah matang untuk refactoring, tetapi mekanismenya ada jika Anda benar-benar membutuhkannya.
Contoh 3:
Ini bisa penting untuk RAII dalam kasus ketika kebutuhan untuk membebaskan sumber daya tidak secara alami "jatuh" ke batas fungsi atau struktur kontrol.
sumber
Ini sangat berguna ketika menggunakan kunci scoped bersama dengan bagian-bagian penting dalam pemrograman multithreaded. Kunci scoped Anda diinisialisasi dalam kurung kurawal (biasanya perintah pertama) akan keluar dari ruang lingkup pada akhir akhir blok dan agar utas lainnya dapat berjalan kembali.
sumber
Semua orang sudah membahas dengan benar kemungkinan pelingkupan, RAII dll., Tetapi karena Anda menyebutkan lingkungan yang disematkan, ada satu alasan potensial lebih lanjut:
Mungkin pengembang tidak mempercayai alokasi register kompiler ini atau ingin secara eksplisit mengontrol ukuran frame stack dengan membatasi jumlah variabel otomatis dalam cakupan sekaligus.
Di sini
isInit
kemungkinan akan ada di tumpukan:Jika Anda mengeluarkan kurung kurawal, ruang untuk
isInit
dapat dicadangkan dalam bingkai tumpukan bahkan setelah berpotensi digunakan kembali: jika ada banyak variabel otomatis dengan cakupan yang sama lokalnya, dan ukuran tumpukan Anda terbatas, itu bisa menjadi masalah.Demikian pula, jika variabel Anda dialokasikan untuk register, keluar dari ruang lingkup harus memberikan petunjuk kuat bahwa register sekarang tersedia untuk digunakan kembali. Anda harus melihat assembler yang dihasilkan dengan dan tanpa kawat gigi untuk mencari tahu apakah ini membuat perbedaan nyata (dan profil itu - atau perhatikan stack overflow - untuk melihat apakah perbedaan ini benar-benar penting).
sumber
Saya pikir orang lain sudah membahas pelingkupan, jadi saya akan menyebutkan kawat gigi yang tidak perlu mungkin juga melayani tujuan dalam proses pengembangan. Misalnya, Anda mengerjakan optimasi untuk fungsi yang sudah ada. Mengalihkan optimisasi atau melacak bug ke urutan pernyataan tertentu mudah bagi programmer - lihat komentar sebelum kawat gigi:
Praktik ini berguna dalam konteks tertentu seperti debugging, perangkat tertanam, atau kode pribadi.
sumber
Saya setuju dengan "ruakh". Jika Anda ingin penjelasan yang baik tentang berbagai tingkat cakupan dalam C, lihat pos ini:
Berbagai Tingkat Lingkup dalam Aplikasi C
Secara umum, penggunaan "Ruang lingkup blok" sangat membantu jika Anda hanya ingin menggunakan variabel sementara yang Anda tidak harus melacak selama panggilan fungsi berlangsung. Selain itu, beberapa orang menggunakannya sehingga Anda dapat menggunakan nama variabel yang sama di beberapa lokasi untuk kenyamanan, meskipun itu umumnya bukan ide yang baik. misalnya:
Dalam contoh khusus ini, saya telah mendefinisikan returnValue dua kali, tetapi karena itu hanya pada ruang lingkup blok, alih-alih ruang lingkup fungsi (yaitu: ruang lingkup fungsi akan, misalnya, menyatakan returnValue tepat setelah int main (void)), saya tidak dapatkan kesalahan kompilator, karena setiap blok tidak menyadari contoh sementara dari returnValue yang dideklarasikan.
Saya tidak bisa mengatakan bahwa ini adalah ide yang baik secara umum (yaitu: Anda mungkin tidak harus menggunakan kembali nama variabel berulang kali dari blok-ke-blok), tetapi secara umum, ini menghemat waktu dan memungkinkan Anda menghindari keharusan mengelola nilai returnValue di seluruh fungsi.
Terakhir, harap perhatikan ruang lingkup variabel yang digunakan dalam sampel kode saya:
sumber
Jadi, mengapa menggunakan kurung kurawal yang tidak perlu?
#pragma
, atau mendefinisikan "bagian" yang dapat divisualisasikan)PS Ini bukan kode BAD; 100% valid. Jadi, ini lebih merupakan masalah rasa (tidak biasa).
sumber
Setelah melihat kode di edit, saya dapat mengatakan bahwa tanda kurung yang tidak perlu mungkin (dalam tampilan coders asli) menjadi 100% jelas apa yang akan terjadi selama if / then, bahkan jika itu hanya satu baris sekarang, mungkin saja lebih banyak baris kemudian, dan kurung menjamin Anda tidak akan membuat kesalahan.
jika di atas adalah asli, dan menghapus "ekstra" akan menghasilkan:
lalu, modifikasi selanjutnya mungkin terlihat seperti ini:
dan itu, tentu saja, akan menimbulkan masalah, karena sekarang isInit akan selalu dikembalikan, terlepas dari jika / kemudian.
sumber
Objek dihancurkan secara otomatis ketika mereka keluar dari ruang lingkup ...
sumber
Contoh lain penggunaan adalah kelas terkait UI, terutama Qt.
Misalnya, Anda memiliki beberapa UI yang rumit dan banyak widget, masing-masing memiliki spasi, tata letak, dll. Daripada menamai mereka,
space1, space2, spaceBetween, layout1, ...
Anda dapat menyelamatkan diri dari nama non-deskriptif untuk variabel yang hanya ada dalam dua-tiga baris kode.Yah, beberapa mungkin mengatakan bahwa Anda harus membaginya dalam metode, tetapi membuat 40 metode yang tidak dapat digunakan kembali tidak terlihat ok - jadi saya memutuskan untuk hanya menambahkan kawat gigi dan komentar di depan mereka, jadi sepertinya blok logis. Contoh:
Tidak bisa mengatakan itu praktik terbaik, tapi bagus untuk kode lama.
Mendapat masalah ini ketika banyak orang menambahkan komponen mereka sendiri ke UI dan beberapa metode menjadi sangat besar, tetapi tidak praktis untuk membuat 40 metode sekali pakai di dalam kelas yang sudah kacau.
sumber