Di C ++, Anda dapat menentukan bahwa suatu fungsi mungkin atau tidak boleh memunculkan pengecualian dengan menggunakan penentu pengecualian. Sebagai contoh:
void foo() throw(); // guaranteed not to throw an exception
void bar() throw(int); // may throw an exception of type int
void baz() throw(...); // may throw an exception of some unspecified type
Saya ragu untuk benar-benar menggunakannya karena hal berikut:
- Kompilator tidak benar-benar menerapkan penentu pengecualian dengan cara apa pun yang ketat, jadi manfaatnya tidak besar. Idealnya, Anda ingin mendapatkan kesalahan kompilasi.
- Jika suatu fungsi melanggar penentu pengecualian, saya pikir perilaku standarnya adalah menghentikan program.
- Di VS.Net, ini memperlakukan lemparan (X) sebagai lemparan (...), jadi kepatuhan terhadap standar tidak kuat.
Apakah menurut Anda penentu pengecualian harus digunakan?
Harap jawab dengan "ya" atau "tidak" dan berikan beberapa alasan untuk membenarkan jawaban Anda.
Jawaban:
Tidak.
Berikut beberapa contoh alasannya:
Kode template tidak mungkin untuk ditulis dengan spesifikasi pengecualian,
Salinan mungkin terlempar, parameter passing mungkin terlempar, dan
x()
mungkin memunculkan beberapa pengecualian yang tidak diketahui.Spesifikasi-pengecualian cenderung melarang ekstensibilitas.
mungkin berkembang menjadi
Anda benar-benar bisa menulisnya sebagai
Yang pertama tidak bisa dikembangkan, yang kedua terlalu ambisius dan yang ketiga benar-benar yang Anda maksud, saat Anda menulis fungsi virtual.
Kode Warisan
Saat Anda menulis kode yang bergantung pada pustaka lain, Anda tidak benar-benar tahu apa yang mungkin dilakukannya jika ada yang tidak beres.
g
akan berhenti, saatlib_f()
melempar. Ini (dalam banyak kasus) bukan yang Anda inginkan.std::terminate()
seharusnya tidak pernah dipanggil. Lebih baik membiarkan aplikasi mogok dengan pengecualian yang tidak tertangani, tempat Anda dapat mengambil pelacakan tumpukan, daripada mati secara diam-diam / keras.Tulis kode yang mengembalikan kesalahan umum dan melempar pada kesempatan luar biasa.
Namun demikian, ketika perpustakaan Anda hanya menampilkan pengecualian Anda sendiri, Anda bisa menggunakan spesifikasi pengecualian untuk menyatakan maksud Anda.
sumber
try {...} catch (<specified exceptions>) { <do whatever> } catch (...) { unexpected(); ]
konstruksi, apakah Anda ingin mencoba blok di sana atau tidak.try { <<...code...>> } catch(...) /* stack guaranteed to be unwound here and dtors run */ { throw; /* pass it on to the runtime */ }
terminate()
? Mengapa tidak menelepon sajaabort()
?Hindari spesifikasi pengecualian di C ++. Alasan yang Anda berikan dalam pertanyaan Anda adalah awal yang cukup bagus untuk alasannya.
Lihat "A Pragmatic Look at Exception Specification" dari Herb Sutter .
sumber
throw(optional-type-id-list)
) tidak digunakan lagi di C ++ 11. Mereka masih dalam standar, tapi saya kira tembakan peringatan telah dikirim yang penggunaannya harus dipertimbangkan dengan hati-hati. C ++ 11 menambahkannoexcept
spesifikasi dan operator. Saya tidak tahu cukup detail tentangnoexcept
mengomentarinya. Artikel ini tampaknya agak rinci: akrzemi1.wordpress.com/2011/06/10/using-noexcept Dan Dietmar Kühl memiliki artikel di Jurnal Overload Juni 2011: accu.org/var/uploads/journals/overload103.pdfthrow(something)
dianggap tidak berguna dan ide yang buruk.throw()
berguna.Saya pikir penentu
pengecualian standar kecuali konvensi (untuk C ++) adalah percobaan dalam standar C ++ yang sebagian besar gagal.
Pengecualiannya adalah bahwa penentu tanpa lemparan berguna tetapi Anda juga harus menambahkan blok try catch yang sesuai secara internal untuk memastikan kode cocok dengan penentu. Herb Sutter memiliki halaman tentang subjek tersebut. Gotch 82
Selain itu, menurut saya, ada baiknya menjelaskan Jaminan Pengecualian.
Ini pada dasarnya adalah dokumentasi tentang bagaimana keadaan suatu objek dipengaruhi oleh pengecualian yang keluar dari metode pada objek itu. Sayangnya mereka tidak diberlakukan atau disebutkan oleh kompilator.
Peningkatan dan Pengecualian
Jaminan Pengecualian
Tidak Ada Jaminan:
Jaminan Dasar:
Jaminan Kuat: (alias Jaminan Transaksional)
Tanpa Jaminan Lempar:
sumber
Guarantee that functions will only throw listed exceptions (possibly none)
. Tidak benar. Ini hanya menjamin bahwa jika fungsi membuang pengecualian ini, aplikasi akan dihentikan.Enable compiler optimizations based on the knowledge that only listed exceptions (possibly none) will be thrown
Tidak bisa melakukan itu. Karena saya baru saja menunjukkan Anda tidak dapat menjamin bahwa pengecualian tidak akan dilempar.throw()
(tidak melempar). " Ini hanya menjamin bahwa jika fungsi tidak membuang pengecualian ini, aplikasi akan menghentikan " Tidak "tidak benar" berarti benar. Tidak ada jaminan di C ++ bahwa suatu fungsi tidak pernah dipanggilterminate()
. " Karena saya baru saja menunjukkan Anda tidak dapat menjamin bahwa pengecualian tidak akan dilempar " Anda menjamin bahwa fungsi tersebut tidak akan dibuang. Itulah yang Anda butuhkan.gcc akan mengeluarkan peringatan jika Anda melanggar spesifikasi pengecualian. Apa yang saya lakukan adalah menggunakan makro untuk menggunakan spesifikasi pengecualian hanya dalam mode "lint" yang dikompilasi secara tersurat untuk memeriksa guna memastikan pengecualian sesuai dengan dokumentasi saya.
sumber
Satu-satunya penentu pengecualian yang berguna adalah "throw ()", seperti dalam "tidak melempar".
sumber
Spesifikasi pengecualian bukanlah alat yang sangat berguna di C ++. Namun, ada / ada / berguna untuk mereka, jika digabungkan dengan std :: tak terduga.
Apa yang saya lakukan di beberapa proyek adalah kode dengan spesifikasi pengecualian, dan kemudian memanggil set_unexpected () dengan fungsi yang akan memunculkan pengecualian khusus untuk desain saya sendiri. Pengecualian ini, saat dibuat, mendapatkan pelacakan balik (dengan cara khusus platform) dan diturunkan dari std :: bad_exception (untuk memungkinkannya disebarkan jika diinginkan). Jika itu menyebabkan panggilan terminate (), seperti biasanya, backtrace dicetak oleh what () (serta pengecualian asli yang menyebabkannya; tidak sulit untuk menemukannya) dan jadi saya mendapatkan informasi di mana kontrak saya berada dilanggar, seperti pengecualian perpustakaan tak terduga yang dilemparkan.
Jika saya melakukan ini, saya tidak pernah mengizinkan propagasi pengecualian perpustakaan (kecuali yang std) dan mendapatkan semua pengecualian saya dari std :: exception. Jika perpustakaan memutuskan untuk membuang, saya akan menangkap dan mengubahnya menjadi hierarki saya sendiri, memungkinkan saya untuk selalu mengontrol kode. Fungsi template yang memanggil fungsi dependen harus menghindari spesifikasi pengecualian karena alasan yang jelas; tetapi jarang memiliki antarmuka fungsi template dengan kode perpustakaan (dan beberapa perpustakaan benar-benar menggunakan template dengan cara yang berguna).
sumber
Jika Anda menulis kode yang akan digunakan oleh orang-orang yang lebih suka melihat deklarasi fungsi daripada komentar di sekitarnya, maka spesifikasi akan memberi tahu mereka pengecualian mana yang mungkin ingin mereka tangkap.
Kalau tidak, saya tidak merasa sangat berguna untuk menggunakan apa pun kecuali
throw()
untuk menunjukkan bahwa itu tidak membuang pengecualian apa pun.sumber
Tidak. Jika Anda menggunakannya dan pengecualian dilemparkan yang tidak Anda tentukan, baik oleh kode Anda atau kode yang dipanggil oleh kode Anda, maka perilaku defaultnya adalah segera menghentikan program Anda.
Selain itu, saya yakin penggunaannya sudah tidak digunakan lagi dalam draf standar C ++ 0x saat ini.
sumber
Spesifikasi "throw ()" memungkinkan compiler melakukan beberapa pengoptimalan saat melakukan analisis aliran kode jika ia tahu bahwa fungsi tersebut tidak akan pernah menampilkan pengecualian (atau setidaknya menjanjikan untuk tidak pernah menampilkan pengecualian). Larry Osterman membicarakan hal ini secara singkat di sini:
http://blogs.msdn.com/larryosterman/archive/2006/03/22/558390.aspx
sumber
Umumnya saya tidak akan menggunakan penentu pengecualian. Namun, dalam kasus di mana jika ada pengecualian lain yang datang dari fungsi tersebut yang programnya pasti tidak dapat mengoreksi , maka ini bisa berguna. Dalam semua kasus, pastikan untuk mendokumentasikan dengan jelas pengecualian apa yang dapat diharapkan dari fungsi itu.
Ya, perilaku yang diharapkan dari pengecualian yang tidak ditentukan yang dilempar dari fungsi dengan penentu pengecualian adalah memanggil terminate ().
Saya juga akan mencatat bahwa Scott Meyers membahas subjek ini dalam C ++ Lebih Efektif. C ++ Efektif dan C ++ Lebih Efektif miliknya adalah buku yang sangat direkomendasikan.
sumber
Ya, jika Anda menyukai dokumentasi internal. Atau mungkin menulis perpustakaan yang akan digunakan orang lain, sehingga mereka dapat mengetahui apa yang terjadi tanpa melihat dokumentasi. Melempar atau tidak melempar bisa dianggap sebagai bagian dari API, hampir seperti nilai yang dikembalikan.
Saya setuju, mereka tidak terlalu berguna untuk menegakkan gaya Java yang benar dalam kompiler, tetapi lebih baik daripada tidak sama sekali atau komentar sembarangan.
sumber
Mereka bisa berguna untuk pengujian unit sehingga saat menulis pengujian Anda tahu apa yang diharapkan fungsi untuk dilempar saat gagal, tetapi tidak ada penegakan yang mengelilinginya di compiler. Saya pikir mereka adalah kode tambahan yang tidak diperlukan di C ++. Apa pun yang Anda pilih, Anda harus yakin bahwa Anda mengikuti standar pengkodean yang sama di seluruh proyek dan anggota tim sehingga kode Anda tetap dapat dibaca.
sumber
Dari artikel:
http://www.boost.org/community/exception_safety.html
Dan memang saya bisa memikirkan cara untuk membuat pengecualian kelas template aman. Kecuali jika Anda tidak memiliki kendali atas semua sub-kelas maka Anda mungkin memiliki masalah. Untuk melakukan ini, Anda dapat membuat typedef di kelas Anda yang menentukan pengecualian yang diberikan oleh berbagai kelas template. Menurut saya, masalahnya adalah selalu memakukannya setelahnya daripada mendesainnya dari awal, dan saya pikir overhead inilah yang menjadi rintangan sebenarnya.
sumber
Spesifikasi pengecualian = sampah, tanyakan pada pengembang Java yang berusia di atas 30 tahun
sumber