Const Superfluous Ekstra buruk dari sudut pandang API:
Menempatkan const berlebihan di kode Anda untuk parameter tipe intrinsik yang diteruskan oleh nilai mengacaukan API Anda sementara tidak membuat janji yang berarti bagi pemanggil atau pengguna API (itu hanya menghambat implementasi).
Terlalu banyak 'const' dalam API ketika tidak diperlukan seperti " menangis serigala ", akhirnya orang akan mulai mengabaikan 'const' karena semuanya ada di mana-mana dan hampir tidak berarti apa-apa.
Argumen "reductio ad absurdum" untuk const tambahan di API baik untuk dua poin pertama ini adalah jika parameter const lebih baik, maka setiap argumen yang dapat memiliki const di atasnya, HARUS memiliki const di atasnya. Bahkan, jika itu benar-benar baik, Anda ingin const menjadi default untuk parameter dan memiliki kata kunci seperti "bisa berubah" hanya ketika Anda ingin mengubah parameter.
Jadi mari kita coba letakkan const di mana pun kita bisa:
void mungerum(char * buffer, const char * mask, int count);
void mungerum(char * const buffer, const char * const mask, const int count);
Pertimbangkan baris kode di atas. Tidak hanya deklarasi yang lebih berantakan dan lebih lama dan lebih sulit untuk dibaca tetapi tiga dari empat kata kunci 'const' dapat diabaikan dengan aman oleh pengguna API. Namun, penggunaan ekstra 'const' telah membuat baris kedua berpotensi BERBAHAYA!
Mengapa?
Kesalahan membaca cepat dari parameter pertama char * const buffer
mungkin membuat Anda berpikir bahwa itu tidak akan mengubah memori dalam buffer data yang diteruskan - namun, ini tidak benar! 'Const' berlebihan dapat menyebabkan asumsi berbahaya dan tidak benar tentang API Anda ketika dipindai atau salah dibaca dengan cepat.
Konstanta yang berlebih buruk dari sudut pandang Implementasi Kode juga:
#if FLEXIBLE_IMPLEMENTATION
#define SUPERFLUOUS_CONST
#else
#define SUPERFLUOUS_CONST const
#endif
void bytecopy(char * SUPERFLUOUS_CONST dest,
const char *source, SUPERFLUOUS_CONST int count);
Jika FLEXIBLE_IMPLEMENTATION tidak benar, maka API "menjanjikan" untuk tidak mengimplementasikan fungsi dengan cara pertama di bawah ini.
void bytecopy(char * SUPERFLUOUS_CONST dest,
const char *source, SUPERFLUOUS_CONST int count)
{
// Will break if !FLEXIBLE_IMPLEMENTATION
while(count--)
{
*dest++=*source++;
}
}
void bytecopy(char * SUPERFLUOUS_CONST dest,
const char *source, SUPERFLUOUS_CONST int count)
{
for(int i=0;i<count;i++)
{
dest[i]=source[i];
}
}
Itu janji yang sangat konyol untuk dibuat. Mengapa Anda harus membuat janji yang sama sekali tidak bermanfaat bagi penelepon Anda dan hanya membatasi implementasi Anda?
Kedua hal ini adalah implementasi yang benar-benar valid dari fungsi yang sama, jadi semua yang Anda lakukan adalah terikat satu tangan di belakang Anda tanpa perlu.
Selain itu, itu adalah janji yang sangat dangkal yang mudah (dan secara hukum dielakkan).
inline void bytecopyWrapped(char * dest,
const char *source, int count)
{
while(count--)
{
*dest++=*source++;
}
}
void bytecopy(char * SUPERFLUOUS_CONST dest,
const char *source,SUPERFLUOUS_CONST int count)
{
bytecopyWrapped(dest, source, count);
}
Lihat, saya menerapkannya bagaimanapun saya berjanji untuk tidak - hanya menggunakan fungsi wrapper. Ini seperti ketika penjahat itu berjanji untuk tidak membunuh seseorang dalam film dan memerintahkan anteknya untuk membunuh mereka.
Konstanta yang berlebihan itu tidak lebih dari janji dari penjahat film.
Tetapi kemampuan untuk berbohong semakin buruk:
Saya telah tercerahkan bahwa Anda dapat ketidakcocokan const di header (deklarasi) dan kode (definisi) dengan menggunakan const palsu. Para pendukung const-happy mengklaim ini adalah hal yang baik karena memungkinkan Anda untuk menempatkan const hanya dalam definisi.
// Example of const only in definition, not declaration
class foo { void test(int *pi); };
void foo::test(int * const pi) { }
Namun, kebalikannya benar ... Anda dapat menempatkan const palsu hanya dalam deklarasi dan mengabaikannya dalam definisi. Ini hanya membuat const berlebihan di API lebih dari hal yang mengerikan dan kebohongan yang mengerikan - lihat contoh ini:
class foo
{
void test(int * const pi);
};
void foo::test(int *pi) // Look, the const in the definition is so superfluous I can ignore it here
{
pi++; // I promised in my definition I wouldn't modify this
}
Semua const yang berlebihan sebenarnya dilakukan adalah membuat kode implementer kurang mudah dibaca dengan memaksanya untuk menggunakan copy lokal atau fungsi wrapper ketika dia ingin mengubah variabel atau meneruskan variabel dengan referensi non-const.
Lihatlah contoh ini. Mana yang lebih mudah dibaca? Apakah jelas bahwa satu-satunya alasan untuk variabel tambahan dalam fungsi kedua adalah karena beberapa perancang API melemparkan konstanta yang berlebihan?
struct llist
{
llist * next;
};
void walkllist(llist *plist)
{
llist *pnext;
while(plist)
{
pnext=plist->next;
walk(plist);
plist=pnext; // This line wouldn't compile if plist was const
}
}
void walkllist(llist * SUPERFLUOUS_CONST plist)
{
llist * pnotconst=plist;
llist *pnext;
while(pnotconst)
{
pnext=pnotconst->next;
walk(pnotconst);
pnotconst=pnext;
}
}
Semoga kita sudah belajar sesuatu di sini. Superfluous const adalah merusak pemandangan API, mengomel menjengkelkan, janji dangkal dan tidak berarti, hambatan yang tidak perlu, dan kadang-kadang menyebabkan kesalahan yang sangat berbahaya.