Menegaskan () ekstensi makro untuk menerapkan penanganan kesalahan minimal

"Tuan, saya datang dengan pertahanan naga." Dia tidak lagi takut pada kita! Ini dipicu oleh mengepakkan sayap naga dan menyalakan sirene keras sehingga semua orang bisa mendengar naga mendekat.
"Apakah pertahanan ini melakukan hal lain?"
"Tidak, mengapa?" Kami akan diperingatkan!
"Ya ... Dimakan oleh sirene yang melolong ... Namun ... mengingatkan kita ketika kita telah merencanakan pemadaman? ...

Deskripsi masalah


Metode ini tidak berpura-pura dengan konsep penanganan kesalahan dalam proyek yang kompleks dan kompleks. Sebaliknya, ini adalah contoh dari apa yang dapat dilakukan dengan cara minimal.

Norma yang baik adalah mengasumsikan bahwa no assert () harus dipicu selama eksekusi program. Dan jika setidaknya satu pernyataan () berfungsi saat menguji aplikasi, maka Anda harus mengirim kesalahan ini ke pengembang. Tetapi, bagaimana jika aplikasi tersebut tidak sepenuhnya diuji? Dan menegaskan () akan bekerja untuk klien? Kirim kesalahan ke pengembang? Batalkan program? Pada kenyataannya, ini akan menjadi versi rilis aplikasi dan pernyataan standar () hanya akan dinonaktifkan. Pertanyaannya juga muncul dengan kontradiksi internal sistem: harus ada banyak penegasan () untuk membuatnya lebih mudah untuk mendeteksi kesalahan, tetapi harus ada lebih sedikit penegasan () untuk kurang mengganggu pengguna dan pekerjaannya dengan aplikasi. Saya terutama tidak ingin "jatuh" jika berapa banyak orang menggunakan aplikasi tergantung pada stabilitas pekerjaan dan jika menegaskan () pada dasarnya tidak signifikan (memerlukan koreksi, tetapi memungkinkan, misalnya, untuk terus berhasil bekerja).

Pertimbangan seperti itu mengarah pada kebutuhan untuk memperbaiki assert () c / c ++. Dan tentukan makro Anda sendiri yang memperluas fungsionalitas standar assert () - tetapi dengan menambahkan penanganan kesalahan minimal. Biarkan makro seperti itu.

VERIFY_EXIT (Ketentuan);
VERIFY_RETURN (Ketentuan, Nilai Pengembalian);
VERIFY_THROW (Ketentuan, Pengecualian);
VERIFY_DO (Kondisi) {/ * blok gagal * /};

(Makro ini juga dapat dipanggil secara berbeda. Misalnya, VERIFY_OR_EXIT (), VERIFY_OR_RETURN (), VERIFY_OR_THROW (), VERIFY_OR_DO (). Atau sebaliknya dalam versi yang lebih pendek.)

Makro ini, pertama, memiliki implementasi untuk versi debug kompilasi dan versi rilis. Itu memungkinkan mereka untuk memiliki perilaku dalam versi rilis program. Yaitu melakukan tindakan tidak hanya selama pengujian, tetapi juga dengan pengguna.

Deskripsi Makro


(Deskripsi makro adalah perkiraan, desain mereka yang lain juga dimungkinkan.)

1) VERIFY_EXIT (Ketentuan);

Ini memeriksa kondisi Kondisi dan jika itu salah, ia memanggil pernyataan standar () (versi debug), dan juga keluar dari fungsi saat ini (versi debug dan rilis).

2) VERIFY_RETURN (Ketentuan, Nilai Pengembalian);

Ini memeriksa kondisi Kondisi dan jika itu salah, ia memanggil pernyataan standar () (versi debug), dan juga keluar dari fungsi saat ini dengan mengembalikan ReturnValue (versi debug dan rilis).

3) VERIFY_THROW (Ketentuan, Pengecualian);

Memeriksa kondisi Kondisi dan jika itu salah, maka ia memanggil pernyataan standar () (versi debug), dan juga melempar Pengecualian (versi debug dan rilis).

4) VERIFY_DO (Kondisi) {/ * blok gagal * /};

Memeriksa kondisi Kondisi dan jika itu salah, ia memanggil pernyataan standar () (versi debug), dan juga melakukan blok gagal atau operasi segera setelah makro (versi debug dan rilis).

Untuk semua makro, penting:

  • Dalam semua kasus, Ketentuan harus benar untuk "melewati" makro dan false untuk mengaktifkan jalur penanganan kesalahan minimal.
  • Setiap makro mengimplementasikan beberapa metode minimal penanganan kesalahan. Ini diperlukan untuk menerapkan perilaku jika terjadi kesalahan yang tidak terdeteksi selama pengujian, tetapi terjadi pada pengguna. Bergantung pada implementasinya, Anda dapat memberi tahu pengembang tentang kesalahan yang terjadi pada klien, tetapi juga setiap implementasi menyediakan cara minimal untuk pulih dari kesalahan.

Pola Penggunaan Makro


Tentu saja, hal yang paling menarik adalah bahwa supermen entropi (pahlawan mengurangi kesalahan dalam program) adalah penggunaan makro ini.

1) Kondisi sebelum dan sesudah.

Kasus penggunaan pertama adalah kondisi sebelum dan sesudah. Biarkan saya mengingatkan Anda bahwa pra kondisi memeriksa keadaan program (masukan argumen, keadaan objek, variabel yang digunakan) untuk kepatuhan dengan persyaratan yang diperlukan dari fragmen kode yang dieksekusi. Kondisi pos (mereka kurang umum dalam program) dimaksudkan untuk memverifikasi bahwa kami telah mencapai hasil yang diinginkan dan bahwa keadaan objek tetap valid untuk fragmen kode saat ini.

Penggunaan makro yang diusulkan sangat mudah - kami menetapkan setiap pemeriksaan dalam makro yang terpisah. Kami memilih makro berdasarkan penanganan kesalahan apa yang kami butuhkan. (VERIFY_EXIT () - pemrosesan kesalahan dengan keluar dari fungsi ini, VERIFY_RETURN () - pemrosesan kesalahan dengan pengembalian nilai, VERRIFY_THROW () - pemrosesan kesalahan dengan pengecualian, dll.)

Anda juga dapat menambahkan atau menggunakan makro VERIFY (), yang tidak akan melakukan penanganan kesalahan. Ini dapat bermanfaat, misalnya dalam kondisi posting di akhir fungsi.

Makro ini sepenuhnya mandiri jika Anda menggunakan prinsip-prinsip kode murni dan mengalokasikan cukup fungsi untuk mengimplementasikan aksi atom. Setiap fungsi dapat memeriksa keadaan suatu objek, memasukkan argumen, dll. untuk melakukan aksi atomnya.

2) Semantik dari suatu transaksi.

Juga, makro ini dapat digunakan untuk mengimplementasikan kode dengan semantik transaksi. Semantik tersebut dipahami sebagai: 1) persiapan bertahap untuk operasi dengan verifikasi hasil masing-masing tahap persiapan; 2) pelaksanaan tindakan hanya jika semua tahap persiapan berhasil; 3) penolakan untuk dipenuhi, jika beberapa kondisi tidak terpenuhi pada tahap persiapan (dengan kemungkinan rollback dari implementasi).

3) Merancang kode, dengan mempertimbangkan kemungkinan ekstensi.

Ini terutama berlaku untuk perpustakaan dan kode umum, yang awalnya dapat dikembangkan dalam konteks kondisi eksekusi tunggal, dan kemudian dapat mulai digunakan dengan kondisi lain (mulai digunakan secara berbeda). Dalam hal ini, makro ini dapat menggambarkan "batas" dari fungsionalitas kode. Tentukan apa yang awalnya dilihat sebagai kesalahan dan apa yang berhasil. (Pendekatan ini dekat dengan kondisi pra posting klasik.) Tentu saja, saya menulis "batas" dalam tanda kutip, karena batas-batas ini dapat direvisi, tetapi penting untuk menentukan (atau lebih tepatnya meneruskan ke pengembang masa depan) pengetahuan tentang batas-batas desain kode yang dapat diterima.

Implementasi makro


Saya berasumsi bahwa sebagian besar pengembang tingkat menengah tidak akan memiliki masalah menerapkan makro ini. Tetapi jika Anda membutuhkan informasi, maka saya akan mencurahkan beberapa poin penting.

Makro harus dapat direpresentasikan sebagai satu pernyataan. Apa yang dapat dilakukan dengan do {} while (false) constructs atau serupa. Misalnya, seperti ini:

#define VERFY_EXIT(cond) \ do{bool _= (bool)(cond); assert(_); if(!_) {return;}} while(false) \ /*end macro VERIFY_EXIT()*/ 

Kemudian Anda dapat menulis kode berikut:

 if(a > 0) VERIFY_EXIT(a%2==0); 

Tentu saja, ini hanya salah satu kemungkinan implementasi. Anda dapat mengimplementasikan makro dengan cara lain.

PS Pertempuran sukses dengan entropi, supermen!

Source: https://habr.com/ru/post/id439172/


All Articles