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 setiap catch
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 menulis catch(...)
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: mendapatkan exception_ptr
untuk meneruskan ke orang lain. Biasanya melalui promise/future
antarmuka atau serupa.
Rekan kerja saya mengatakan bahwa Anda harus selalu tahu pengecualian apa yang harus dilempar dan bahwa Anda selalu dapat menggunakan konstruksi seperti:
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.
...
" sementara pertanyaan saya fokus pada "Haruskah saya menangkap...
atau<specific exception>
sebelum memasang kembali"