Ini adalah contoh dari apa yang sering saya lakukan ketika saya ingin menambahkan beberapa informasi ke pengecualian:
std::stringstream errMsg;
errMsg << "Could not load config file '" << configfile << "'";
throw std::exception(errMsg.str().c_str());
Apakah ada cara yang lebih baik untuk melakukannya?
std∷exception
tidak memiliki konstruktor denganchar*
arg.std::string
memiliki konstruktor implisit yang mengambilconst char*
...std::exception
kelas anak, dan digunakan oleh versistd::runtime_error
danstd::logic_error
. Terlepas dari yang ditentukan oleh standar, versi MSVS<exception>
juga mencakup dua lagi konstruktor, satu pengambilan(const char * const &)
dan pengambilan lainnya(const char * const &, int)
. Mereka digunakan untuk mengatur variabel pribadi,const char * _Mywhat
; jika_Mywhat != nullptr
, maka secarawhat()
default mengembalikannya. Kode yang bergantung padanya mungkin tidak portabel.Jawaban:
Inilah solusi saya:
Contoh:
sumber
Pengecualian standar dapat dibuat dari
std::string
:Perhatikan bahwa kelas dasar tidak
std::exception
bisa dibangun sehingga; Anda harus menggunakan salah satu kelas turunan yang konkret.sumber
Ada pengecualian yang berbeda seperti
runtime_error
,range_error
,overflow_error
,logic_error
, dll .. Anda harus lulus string ke konstruktor, dan Anda dapat menggabungkan apa pun yang Anda ingin pesan Anda. Itu hanya operasi string.Anda juga bisa menggunakan
boost::format
seperti ini:sumber
Kelas berikut mungkin cukup berguna:
Contoh penggunaan:
sumber
throw std::runtime_error(sprintf("Could not load config file '%s'", configfile.c_str()))
throw std::runtime_error("Could not load config file " + configfile);
(mengonversi satu atau argumen lain menjadistd::string
jika perlu).printf
dan teman-teman akan segera hadir di C ++ 11. Buffer ukuran tetap adalah berkah dan kutukan: itu tidak gagal dalam situasi sumber daya rendah tetapi dapat memotong pesan. Saya menganggap memotong pesan kesalahan sebagai opsi yang lebih baik kemudian gagal. Selain itu, kenyamanan string format telah dibuktikan oleh banyak bahasa berbeda. Tetapi Anda benar, ini sebagian besar adalah masalah selera.Gunakan operator literal string jika C ++ 14 (
operator ""s
)atau tentukan sendiri jika dalam C ++ 11. Misalnya
Pernyataan lemparan Anda akan terlihat seperti ini
yang terlihat bagus dan bersih.
sumber
Cara yang lebih bagus adalah membuat kelas (atau kelas) untuk pengecualian.
Sesuatu seperti:
Alasannya adalah bahwa pengecualian jauh lebih disukai daripada hanya mentransfer string. Menyediakan kelas yang berbeda untuk kesalahan, Anda memberi pengembang kesempatan untuk menangani kesalahan tertentu dengan cara yang sesuai (tidak hanya menampilkan pesan kesalahan). Orang yang menangkap pengecualian Anda bisa sespesifik yang mereka butuhkan jika Anda menggunakan hierarki.
a) Seseorang mungkin perlu mengetahui alasan spesifiknya
a) orang lain tidak ingin mengetahui detailnya
Anda dapat menemukan beberapa inspirasi tentang topik ini di https://books.google.ru/books?id=6tjfmnKhT24C Bab 9
Selain itu, Anda juga dapat memberikan pesan khusus, tetapi hati-hati - tidak aman untuk membuat pesan dengan salah satu
std::string
ataustd::stringstream
atau cara lain yang dapat menyebabkan pengecualian .Secara umum, tidak ada perbedaan apakah Anda mengalokasikan memori (bekerja dengan string dengan cara C ++) dalam konstruktor pengecualian atau tepat sebelum melempar -
std::bad_alloc
pengecualian dapat dilemparkan sebelum yang Anda inginkan.Jadi, buffer yang dialokasikan di stack (seperti dalam jawaban Maxim) adalah cara yang lebih aman.
Ini dijelaskan dengan sangat baik di http://www.boost.org/community/error_handling.html
Jadi, cara yang lebih baik adalah jenis pengecualian tertentu dan menghindari penulisan string yang diformat (setidaknya saat melempar).
sumber
Mengalami masalah serupa, di mana membuat pesan kesalahan khusus untuk pengecualian khusus saya membuat kode jelek. Ini adalah solusi saya:
Ini memisahkan logika untuk membuat pesan. Saya awalnya berpikir untuk menimpa what (), tapi kemudian Anda harus menangkap pesan Anda di suatu tempat. std :: runtime_error sudah memiliki buffer internal.
sumber
Mungkin ini?
Ini membuat ostringstream sementara, memanggil operator << seperlunya dan kemudian Anda membungkusnya dalam tanda kurung bulat dan memanggil fungsi .str () pada hasil yang dievaluasi (yang merupakan ostringstream) untuk meneruskan std :: string sementara ke konstruktor dari runtime_error.
Catatan: ostringstream dan string adalah temporer nilai-r dan keluar dari ruang lingkup setelah baris ini berakhir. Konstruktor objek pengecualian Anda HARUS mengambil string input menggunakan semantik salin atau pindah (lebih baik).
Tambahan: Saya tidak menganggap pendekatan ini sebagai "praktik terbaik", tetapi berhasil dan dapat digunakan dalam keadaan darurat. Salah satu masalah terbesar adalah bahwa metode ini memerlukan alokasi heap sehingga operator << dapat membuangnya. Anda mungkin tidak ingin itu terjadi; Namun, jika Anda masuk ke keadaan itu, Anda mungkin memiliki lebih banyak masalah untuk dikhawatirkan!
sumber