Saya menyadari bahwa sementara pertanyaan tidak memiliki tag bahasa, itu mungkin secara implisit berbicara tentang "bahasa kopi". Tapi hanya demi kelengkapan, saya ingin menyebutkan konsensus yang agak menyimpang di dunia C ++.
Ada tiga hal yang biasanya diminati oleh programmer C ++:
- Apakah ini memiliki nol overhead dalam build yang dioptimalkan? (Yaitu, bisakah itu "dikompilasi"?)
- Bisakah saya menggunakannya untuk menjebak debugger tepat pada titik di mana kesalahan terdeteksi?
- Bisakah saya menggunakannya untuk melaporkan masalah dari fungsi yang dideklarasikan
noexcept
?
Di masa lalu, saya telah mendekati masalah pertama dengan menulis kode seperti ini
int
factorial(const int n)
{
if (CHECK_ARGS)
{
if (n < 0)
throw std::invalid_argument {"n < 0"};
}
int fac = 1;
for (int i = 2; i <= n; ++i)
fac *= i;
return fac;
}
mana CHECK_ARGS
yang #define
d ke waktu kompilasi konstan sehingga compiler dapat sepenuhnya menghilangkan semua argumen kode pengecekan di dioptimalkan membangun. (Saya tidak mengatakan bahwa mengkompilasi cek adalah hal yang baik secara umum, tetapi saya percaya bahwa pengguna harus memiliki opsi untuk mengkompilasinya.)
Saya masih suka tentang solusi ini bahwa kode pemeriksaan argumen terlihat jelas dikelompokkan bersama ke dalam if
. Namun, masalah kedua dan ketiga tidak terpecahkan dengan ini. Oleh karena itu, saya sekarang lebih condong ke arah menggunakan assert
makro untuk memeriksa argumen.
Standar pengkodean Boost setuju dengan ini:
Bagaimana dengan Kesalahan Programmer?
Sebagai pengembang, jika saya melanggar prasyarat perpustakaan yang saya gunakan, saya tidak ingin tumpukan dibuka. Apa yang saya inginkan adalah dump inti atau yang setara - cara untuk memeriksa status program pada titik yang tepat di mana masalah terdeteksi. Itu biasanya berarti assert()
atau sesuatu seperti itu.
Ada ceramah yang sangat menarik yang diberikan oleh John Lakos di CppCon'14 berjudul Defensive Programming Done Right ( bagian 1 , bagian 2 ). Pada bagian pertama ceramahnya, ia membahas teori kontrak dan perilaku yang tidak terdefinisi. Pada bagian kedua, dia menyajikan apa yang saya anggap proposal yang sangat bagus untuk pemeriksaan argumen sistematis. Pada dasarnya, ia mengusulkan makro pernyataan yang memungkinkan pengguna untuk memilih berapa banyak anggaran (dalam hal penggunaan CPU) dia bersedia menyumbang ke perpustakaan untuk memeriksa argumen dan membuat perpustakaan bijaksana menggunakan anggaran itu. Sebagai tambahan, pengguna juga dapat menginstal fungsi penanganan kesalahan global yang akan dipanggil jika kontrak yang rusak terdeteksi.
Mengenai aspek bahwa suatu fungsi bersifat pribadi, saya tidak berpikir bahwa ini berarti kita seharusnya tidak pernah memeriksa argumennya. Kita mungkin lebih mempercayai kode kita sendiri untuk tidak melanggar kontrak fungsi internal tetapi kita juga tahu bahwa kita juga tidak sempurna. Mengecek argumen dalam fungsi internal sama membantu dalam mendeteksi bug kita sendiri seperti halnya dalam fungsi publik untuk mendeteksi bug dalam kode klien.