Saya pernah disarankan bahwa program C ++ pada akhirnya harus menangkap semua pengecualian. Alasan yang diberikan pada saat itu pada dasarnya adalah bahwa program yang memungkinkan pengecualian muncul di luar main()
memasuki keadaan zombie yang aneh. Saya diberitahu ini beberapa tahun yang lalu dan dalam retrospeksi saya percaya fenomena yang diamati adalah karena generasi panjang dump inti sangat besar dari proyek tersebut.
Pada saat itu ini tampak aneh tetapi meyakinkan. Itu benar-benar tidak masuk akal bahwa C ++ harus "menghukum" programmer karena tidak menangkap semua pengecualian tetapi bukti sebelum saya tampaknya mendukung hal ini. Untuk proyek yang dimaksud, program yang melemparkan pengecualian tanpa tertangkap tampaknya memasuki keadaan zombie yang aneh - atau seperti yang saya duga penyebabnya sekarang, proses di tengah-tengah pembuangan inti yang tidak diinginkan biasanya sulit untuk dihentikan.
(Bagi siapa pun yang bertanya-tanya mengapa hal ini tidak lebih jelas pada saat itu: Proyek ini menghasilkan sejumlah besar output dalam banyak file dari berbagai proses yang secara efektif mengaburkan semua jenis aborted (core dumped)
pesan dan dalam kasus khusus ini, pemeriksaan post-mortem untuk dump inti tidak dilakukan. itu adalah teknik debugging yang penting sehingga dump inti tidak banyak dipikirkan. Masalah dengan suatu program biasanya tidak tergantung pada akumulasi dari banyak peristiwa dari waktu ke waktu oleh program yang berumur panjang melainkan input awal untuk program yang berumur pendek (< 1 jam) jadi lebih praktis untuk hanya menjalankan kembali program dengan input yang sama dari debug build atau di debugger untuk mendapatkan info lebih lanjut.)
Saat ini, saya tidak yakin apakah ada keuntungan atau kerugian besar dari menangkap pengecualian hanya untuk tujuan mencegah pengecualian pergi main()
.
Keuntungan kecil yang dapat saya pikirkan untuk memungkinkan pengecualian untuk muncul main()
adalah bahwa hal itu menyebabkan hasil std::exception::what()
untuk dicetak ke terminal (setidaknya dengan program yang dikompilasi gcc di Linux). Di sisi lain, ini sepele untuk dicapai dengan alih-alih menangkap semua pengecualian yang berasal dari std::exception
dan mencetak hasil std::exception::what()
dan jika diinginkan untuk mencetak pesan dari pengecualian yang tidak berasal dari std::exception
maka harus ditangkap sebelum pergi main()
untuk mencetak pesan.
Kerugian sederhana yang dapat saya pikirkan untuk memungkinkan pengecualian untuk menggelembungkan masa lalu main()
adalah bahwa dump inti yang tidak diinginkan dapat dihasilkan. Untuk proses yang menggunakan memori dalam jumlah besar, ini bisa menjadi gangguan dan mengendalikan perilaku dumping inti dari suatu program membutuhkan pemanggilan fungsi spesifik OS. Di sisi lain, jika sebuah core dump dan exit diinginkan maka ini dapat dicapai setiap saat dengan menelepon std::abort()
dan keluar tanpa core dump dapat dicapai kapan saja dengan menelepon std::exit()
.
Secara anekdot, saya rasa saya tidak pernah melihat what(): ...
pesan default dicetak oleh program yang didistribusikan secara luas saat mogok.
Apa, jika ada, argumen kuat untuk atau tidak memungkinkan pengecualian C ++ meluap melewati main()
?
Sunting: Ada banyak pengecualian umum yang menangani pertanyaan di situs ini. Pertanyaan saya secara khusus tentang pengecualian C ++ yang tidak dapat ditangani dan berhasil sampai ke sana main()
- mungkin pesan kesalahan dapat dicetak tetapi ini segera menunjukkan kesalahan berhenti.
sumber
Jawaban:
Satu masalah dengan membiarkan pengecualian melewati main adalah bahwa program akan diakhiri dengan panggilan
std::terminate
yang merupakan perilaku default untuk dipanggilstd::abort
. Ini hanya implementasi yang ditentukan jika stack unwinding dilakukan sebelum memanggilterminate
sehingga program Anda dapat berakhir tanpa memanggil satu destruktor! Jika Anda memiliki beberapa sumber daya yang benar-benar perlu dipulihkan oleh panggilan destruktor, Anda berada dalam ...sumber
std::abort
tidak dan dengan demikian pernyataan yang gagal juga tidak. Penting juga untuk dicatat bahwa pada OS modern, OS itu sendiri akan membersihkan banyak sumber daya (memori, file handle, ...) yang terkait dengan proses ID. Akhirnya, saya juga mengisyaratkan "Pertahanan dalam Kedalaman": tidak dapat diandalkan untuk mengharapkan bahwa semua proses lain adalah anti-bug dan akan selalu merilis sumber daya yang mereka peroleh (sesi, selesai menulis file, ...) Anda harus merencanakan untuk itu ...WM_POWERBROADCAST
pesannya. Ini hanya berfungsi jika komputer Anda bertenaga baterai (jika Anda menggunakan laptop atau UPS).Alasan utama untuk tidak membiarkan pengecualian lolos
main
adalah karena jika tidak, Anda kehilangan semua kemungkinan untuk mengontrol bagaimana masalah dilaporkan kepada pengguna Anda.Untuk program yang tidak dimaksudkan untuk digunakan dalam waktu lama atau didistribusikan secara luas, dapat diterima bahwa kesalahan tak terduga dilaporkan dengan cara apa pun yang diputuskan oleh OS untuk melakukannya (misalnya, menampilkan dialog kesalahan di wajah Anda pada Windows ).
Untuk program yang Anda jual, atau yang disediakan untuk masyarakat umum oleh organisasi yang memiliki reputasi untuk ditegakkan, umumnya merupakan ide yang lebih baik untuk melaporkan dengan cara yang baik bahwa Anda menghadapi masalah yang tidak terduga dan mencoba untuk menyimpan sebanyak mungkin data pengguna mungkin. Tidak kehilangan pekerjaan setengah hari dari pengguna Anda dan tidak crash secara tiba-tiba, tetapi mematikan secara semi-anggun umumnya jauh lebih baik untuk reputasi bisnis Anda daripada alternatifnya.
sumber
main()
banyak hubungannya dengan OS? OS mungkin tidak tahu apa-apa tentang C ++. Dugaan saya adalah bahwa itu ditentukan oleh kode penyusun sisipan di suatu tempat ke dalam program.TL; DR : Apa spesifikasinya katakan?
Jalan memutar teknis ...
Ketika pengecualian dilemparkan dan tidak ada pawang yang siap untuk itu:
std::terminate
disebut, yang secara default dibatalkanYang terakhir ini dapat berguna untuk bug yang sangat jarang (karena mereproduksi mereka adalah proses yang menghabiskan waktu).
Apakah untuk menangkap semua pengecualian atau tidak, pada akhirnya, adalah masalah spesifikasi:
Untuk setiap program produksi, ini harus ditentukan, dan Anda harus mengikuti spesifikasi (dan mungkin berpendapat bahwa itu diubah).
Untuk dengan cepat menggabungkan program yang hanya dapat digunakan oleh orang-orang teknis (Anda, rekan tim Anda), keduanya baik-baik saja. Saya sarankan membiarkannya macet dan mengatur lingkungan untuk mendapatkan laporan atau tidak tergantung pada kebutuhan Anda.
sumber
Pengecualian yang Anda tangkap memberi Anda kesempatan untuk mencetak pesan kesalahan yang bagus atau bahkan mencoba memulihkan dari kesalahan (mungkin dengan hanya meluncurkan ulang aplikasi).
Namun, dalam C ++ pengecualian tidak menyimpan informasi tentang status program saat dilempar. Jika Anda menangkapnya, semua status seperti itu dilupakan, sedangkan jika Anda membiarkan program macet, keadaan biasanya masih ada dan dapat dibaca dari dump program, sehingga lebih mudah untuk debug.
Jadi itu adalah trade-off.
sumber
Saat Anda tahu Anda harus membatalkan, silakan dan telepon
std::terminate
sudah untuk mengurangi kerusakan lebih lanjut.Jika Anda tahu Anda dapat beristirahat dengan aman, lakukan itu. Ingat bahwa tumpukan-gulungan tidak dijamin ketika pengecualian tidak pernah ditangkap, jadi tangkap dan rethrow.
Jika Anda dapat dengan aman melaporkan / mencatat kesalahan lebih baik daripada sistem akan melakukannya sendiri, silakan.
Tetapi pastikan benar-benar untuk tidak secara tidak sengaja memperburuk keadaan saat melakukannya.
Seringkali sudah terlambat untuk menyimpan data ketika Anda mendeteksi kesalahan yang tidak dapat dipulihkan, meskipun itu tergantung pada kesalahan spesifik.
Lagi pula, jika program Anda ditulis untuk pemulihan cepat, mematikannya mungkin merupakan cara terbaik untuk mengakhirinya bahkan jika itu hanya shutdown biasa.
sumber
Menabrak dengan anggun adalah hal yang baik sebagian besar waktu - tetapi ada trade-off. Terkadang bagus untuk crash. Saya harus menyebutkan bahwa saya kebanyakan berpikir tentang debugging dalam ukuran yang sangat besar. Untuk program yang sederhana - walaupun ini mungkin masih berguna, ini sama sekali tidak membantu dengan program yang sangat kompleks (atau beberapa program kompleks yang berinteraksi).
Anda tidak ingin crash di depan umum (walaupun ini benar-benar tidak dapat dihindari - program crash, dan program non-crash yang benar-benar dapat diverifikasi secara matematis bukanlah yang sedang kita bicarakan di sini). Pikirkan Bill Gates BSODing di tengah-tengah demo - buruk, bukan? Meskipun demikian, kita dapat mencoba mencari tahu mengapa kita crash dan tidak crash lagi dengan cara yang sama.
Saya menyalakan fitur Windows Error Reporting yang membuat crash crashs lokal pada pengecualian yang tidak tertangani. Ini berfungsi dengan baik jika Anda memiliki file simbol yang terkait dengan build (macet) Anda. Cukup menarik, karena saya mengatur alat ini, saya ingin crash lebih banyak - karena saya belajar dari setiap crash. Lalu saya bisa memperbaiki bug dan mengurangi crash.
Jadi untuk sekarang, saya ingin program saya membuang semua jalan ke atas dan crash. Di masa depan, saya mungkin ingin memakan semua pengecualian saya dengan anggun - tetapi tidak jika saya bisa membuatnya bekerja untuk saya.
Anda dapat membaca lebih lanjut tentang Tumpukan Kecelakaan Lokal di sini jika Anda tertarik: Mengumpulkan Dump Mode Pengguna
sumber
Pada akhirnya, jika pengecualian muncul di atas main (), itu akan merusak aplikasi Anda, dan dalam pikiran saya sebuah aplikasi seharusnya tidak pernah crash. Jika OK untuk crash aplikasi di satu tempat, lalu mengapa tidak di mana saja? Mengapa repot dengan penanganan pengecualian? (Sarkasme, tidak benar-benar menyarankan ini ...)
Anda mungkin memiliki global mencoba / menangkap yang mencetak pesan yang elegan memberitahu pengguna bahwa telah terjadi kesalahan yang tidak dapat dipulihkan dan bahwa mereka perlu mengirim email kepada bob tentang hal itu atau sesuatu yang serupa, tetapi menabrak benar-benar tidak profesional dan tidak dapat diterima. Sepele untuk dicegah dan Anda dapat memberi tahu pengguna tentang apa yang baru saja terjadi dan bagaimana cara memperbaikinya agar tidak terjadi lagi.
Kecelakaan adalah jam yang sangat amatir.
sumber
main
. Jika Anda tidak tahu cara menanganinya, berpura-pura melakukannya jelas merupakan bug yang sangat mengerikan.