Meskipun saya setuju bahwa menangkap ...
tanpa rethrowing memang salah, namun saya percaya bahwa menggunakan konstruksi seperti ini:
try
{
// Stuff
}
catch (...)
{
// Some cleanup
throw;
}
Dapat diterima dalam kasus di mana RAII tidak berlaku . (Tolong, jangan tanya ... tidak semua orang di perusahaan saya suka pemrograman berorientasi objek dan RAII sering dianggap sebagai "barang sekolah yang tidak berguna" ...)
Rekan kerja saya mengatakan bahwa Anda harus selalu tahu pengecualian apa yang harus dilempar dan bahwa Anda selalu dapat menggunakan konstruksi seperti:
try
{
// Stuff
}
catch (exception_type1&)
{
// Some cleanup
throw;
}
catch (exception_type2&)
{
// Some cleanup
throw;
}
catch (exception_type3&)
{
// Some cleanup
throw;
}
Apakah ada praktik baik yang diakui tentang situasi ini?
...
" sementara pertanyaan saya fokus pada "Haruskah saya menangkap...
atau<specific exception>
sebelum memasang kembali"main
,catch(...) { return EXIT_FAILURE; }
mungkin benar dalam kode yang tidak berjalan di bawah debugger. Jika Anda tidak menangkap, maka tumpukan mungkin tidak terlepas. Hanya ketika debugger Anda mendeteksi pengecualian yang tidak diinginkan, Anda ingin mereka pergimain
.Jawaban:
Rekan kerja Anda, saya benci mengatakannya, jelas tidak pernah bekerja di perpustakaan untuk tujuan umum.
Bagaimana mungkin sebuah kelas seperti
std::vector
bahkan berpura - pura tahu apa yang akan dibuang oleh copy constructor, sambil tetap menjamin keamanan pengecualian?Jika Anda selalu tahu apa yang akan dilakukan callee pada waktu kompilasi, maka polimorfisme tidak akan berguna! Terkadang seluruh tujuan adalah untuk mengabstraksi apa yang terjadi di tingkat yang lebih rendah, sehingga Anda secara khusus tidak ingin tahu apa yang terjadi!
sumber
...
?Apa yang tampaknya membuat Anda terperangkap adalah neraka seseorang yang mencoba memiliki kue mereka dan memakannya juga.
RAII dan pengecualian dirancang untuk berjalan beriringan. RAII adalah cara dengan mana Anda tidak memiliki untuk menulis banyak
catch(...)
pernyataan untuk melakukan pembersihan. Tentu saja itu akan terjadi secara otomatis. Dan pengecualian adalah satu-satunya cara untuk bekerja dengan objek RAII, karena konstruktor hanya dapat berhasil atau melempar (atau meletakkan objek dalam status kesalahan, tetapi siapa yang mau itu?).Sebuah
catch
pernyataan dapat melakukan salah satu dari dua hal: menangani kesalahan atau keadaan luar biasa, atau melakukan pekerjaan pembersihan. Kadang-kadang memang keduanya, tetapi setiapcatch
pernyataan ada untuk melakukan setidaknya satu dari ini.catch(...)
tidak mampu melakukan penanganan pengecualian yang tepat. Anda tidak tahu apa pengecualiannya; Anda tidak dapat memperoleh informasi tentang pengecualian. Anda sama sekali tidak memiliki informasi selain fakta bahwa pengecualian dilemparkan oleh sesuatu di dalam blok kode tertentu. Satu-satunya hal yang sah yang dapat Anda lakukan di blok tersebut adalah melakukan pembersihan. Dan itu berarti melemparkan kembali pengecualian di akhir pembersihan.Apa yang RAII berikan kepada Anda sehubungan dengan penanganan pengecualian adalah pembersihan gratis. Jika semuanya dirangkum dengan benar, maka semuanya akan dibersihkan dengan benar. Anda tidak perlu lagi memiliki
catch
laporan pembersihan. Dalam hal ini, tidak ada alasan untuk menuliscatch(...)
pernyataan.Jadi saya setuju bahwa
catch(...)
itu sebagian besar jahat ... sementara .Ketentuan itu menjadi penggunaan RAII yang tepat. Karena tanpa itu, Anda harus dapat melakukan pembersihan tertentu. Tidak ada jalan lain; Anda harus dapat melakukan pekerjaan pembersihan. Anda harus dapat memastikan bahwa melemparkan pengecualian akan meninggalkan kode dalam keadaan yang masuk akal. Dan
catch(...)
merupakan alat vital dalam melakukannya.Anda tidak dapat memiliki satu tanpa yang lain. Anda tidak bisa mengatakan bahwa keduanya RAII dan
catch(...)
buruk. Anda memerlukan setidaknya satu dari ini; jika tidak, Anda tidak terkecuali aman.Tentu saja, ada satu penggunaan sah-meskipun-jarang
catch(...)
yang bahkan RAII tidak bisa usir: mendapatkanexception_ptr
untuk meneruskan ke orang lain. Biasanya melaluipromise/future
antarmuka atau serupa.Rekan kerja Anda adalah seorang idiot (atau hanya sangat bodoh). Ini harus segera jelas karena berapa banyak kode salin dan rekat yang dia sarankan untuk Anda tulis. Pembersihan untuk masing-masing pernyataan tangkapan akan persis sama . Itu adalah mimpi buruk pemeliharaan, belum lagi keterbacaan.
Singkatnya: ini adalah masalah yang RAII diciptakan untuk menyelesaikannya (bukan karena itu tidak menyelesaikan masalah lain).
Yang membingungkan saya tentang gagasan ini adalah bahwa pada umumnya mundur ke bagaimana kebanyakan orang berpendapat bahwa RAII buruk. Secara umum, argumen tersebut berbunyi, "RAII buruk karena Anda harus menggunakan pengecualian untuk memberi sinyal kegagalan konstruktor. Tetapi Anda tidak dapat membuang pengecualian, karena itu tidak aman dan Anda harus memiliki banyak
catch
pernyataan untuk membersihkan semuanya." Yang merupakan argumen yang rusak karena RAII memecahkan masalah yang diciptakan oleh kurangnya RAII.Kemungkinan besar, dia menentang RAII karena menyembunyikan detail. Panggilan destruktor tidak langsung terlihat pada variabel otomatis. Jadi Anda mendapatkan kode yang dipanggil secara implisit. Beberapa programmer sangat membenci itu. Rupanya, ke titik di mana mereka berpikir memiliki 3
catch
pernyataan, yang semuanya melakukan hal yang sama dengan kode salin dan tempel adalah ide yang lebih baik.sumber
Dua komentar, sungguh. Yang pertama adalah bahwa sementara di dunia yang ideal, Anda harus selalu tahu pengecualian apa yang mungkin dilemparkan, dalam praktiknya, jika Anda berurusan dengan perpustakaan pihak ketiga, atau kompilasi dengan kompiler Microsoft, Anda tidak. Lebih tepatnya,; bahkan jika Anda tahu persis semua pengecualian yang mungkin, apakah itu relevan di sini?
catch (...)
menyatakan niatnya jauh lebih baik daripadacatch ( std::exception const& )
, bahkan seandainya semua pengecualian yang mungkin berasal daristd::exception
(yang akan menjadi kasus di dunia yang ideal). Adapun untuk menggunakan beberapa blok tangkap, jika tidak ada pangkalan umum untuk semua pengecualian: itu benar-benar membingungkan, dan mimpi buruk pemeliharaan. Bagaimana Anda mengenali bahwa semua perilaku itu identik? Dan itu maksudnya? Dan apa yang terjadi jika Anda harus mengubah perilaku (perbaikan bug, misalnya)? Terlalu mudah untuk melewatkannya.sumber
std::exception
dan mencoba setiap hari untuk menegakkan penggunaannya di antara basis kode kami. Dugaan saya adalah ia mencoba menghukum saya karena menggunakan kode dan perpustakaan eksternal yang belum ia tulis sendiri.std::vector<>
dapat membuang segala macam pengecualian untuk alasan apa pun.Saya pikir rekan kerja Anda telah mencampuradukkan beberapa saran yang bagus - Anda hanya harus menangani pengecualian yang diketahui dalam satu
catch
blok ketika Anda tidak melemparkannya kembali.Ini berarti:
Apakah buruk karena diam-diam akan menyembunyikan apa pun kesalahan.
Namun:
Tidak apa-apa - kita tahu apa yang sedang kita hadapi dan tidak perlu memaparkannya ke kode panggilan.
Juga:
Baik-baik saja, bahkan praktik terbaik, kode untuk menangani kesalahan umum harus dengan kode yang menyebabkannya. Lebih baik daripada mengandalkan callee untuk mengetahui bahwa suatu transaksi perlu dibatalkan atau apa pun.
sumber
Setiap jawaban ya atau tidak harus disertai dengan alasan mengapa demikian.
Mengatakan itu salah hanya karena saya diajarkan bahwa itu hanyalah fanatisme buta.
Menulis
//Some cleanup; throw
beberapa kali sama , seperti dalam contoh Anda salah karena duplikasi kode dan itu adalah beban pemeliharaan. Menulisnya sekali saja lebih baik.Menulis
catch(...)
untuk membungkam semua pengecualian adalah salah karena Anda hanya harus menangani pengecualian yang Anda tahu bagaimana menangani, dan dengan wildcard itu Anda dapat memperoleh lebih dari yang Anda harapkan, dan melakukannya dapat membungkam kesalahan penting.Tetapi jika Anda melakukan rethrow setelah a
catch(...)
, maka alasan terakhir tidak berlaku lagi, karena Anda sebenarnya tidak menangani pengecualian, jadi tidak ada alasan mengapa ini harus dicegah.Sebenarnya saya sudah melakukan ini untuk masuk ke fungsi sensitif tanpa masalah apa pun:
sumber
Log(...)
tidak bisa melempar.Saya umumnya setuju dengan mood posting di sini, saya benar-benar tidak menyukai pola menangkap pengecualian khusus - saya pikir sintaksnya masih dalam masa pertumbuhan dan belum dapat mengatasi kode yang berlebihan.
Tetapi karena semua orang mengatakan itu, saya akan menyatu dengan fakta bahwa meskipun saya menggunakannya dengan hemat, saya sering melihat salah satu pernyataan "tangkapan (pengecualian)" saya dan berkata, "Sial, saya berharap saya sudah menelepon mengeluarkan pengecualian khusus pada saat itu "karena ketika Anda masuk nanti sering kali menyenangkan mengetahui apa maksudnya dan apa yang akan dilirik klien sekilas.
Saya tidak membenarkan sikap "Selalu gunakan x", hanya mengatakan bahwa kadang-kadang memang menyenangkan melihat mereka terdaftar dan saya yakin itu sebabnya beberapa orang berpikir itu cara "Benar" untuk melangkah.
sumber