Ekstra Gereksiz const, bir API açısından kötüdür:
Değerden geçirilen gerçek tip parametreler için kodunuza fazladan gereksiz const koymak, API'nızı arayarak API veya API kullanıcısına anlamlı bir söz vermez (yalnızca uygulamayı engeller).
Bir API'de ihtiyaç duyulmadığında çok fazla 'const' " ağlayan kurt " gibidir, sonunda insanlar 'const'u görmezden gelmeye başlar, çünkü her yerde vardır ve çoğu zaman hiçbir şey ifade etmez.
API'da ekstra consts için "reductio ad absurdum" argümanı, bu ilk iki nokta için iyidir, daha fazla const parametresi iyi ise, o zaman bir const olabilecek her argümanın üzerinde bir const olması gerekir. Aslında, gerçekten iyi olsaydı, const'un parametreler için varsayılan olmasını ve yalnızca parametreyi değiştirmek istediğinizde "mutable" gibi bir anahtar kelimeye sahip olmasını istersiniz.
Yani, mümkün olan her yerde const koymayı deneyelim:
void mungerum(char * buffer, const char * mask, int count);
void mungerum(char * const buffer, const char * const mask, const int count);
Yukarıdaki kod satırını düşünün. Beyan sadece daha karmaşık ve uzun ve okunması daha zor olmakla kalmaz, aynı zamanda dört 'const' anahtar kelimeden üçü API kullanıcısı tarafından güvenli bir şekilde göz ardı edilebilir. Bununla birlikte, 'const'un ekstra kullanımı ikinci satırı potansiyel olarak TEHLİKELİ hale getirdi !
Neden?
İlk parametrenin hızlı bir şekilde yanlış okunması char * const buffer
, aktarılan veri arabelleğindeki belleği değiştirmeyeceğini düşünmenizi sağlayabilir - ancak bu doğru değildir! Gereksiz 'const', hızlı bir şekilde tarandığında veya yanlış okunduğunda API'nız hakkında tehlikeli ve yanlış varsayımlara yol açabilir .
Gereksiz yapı, Kod Uygulama açısından da kötüdür:
#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);
FLEXIBLE_IMPLEMENTATION doğru değilse, API işlevi ilk yoldan uygulamaya koymamak için “umut vericidir”.
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];
}
}
Bu çok aptalca bir söz. Neden arayana hiç fayda sağlamayan ve sadece uygulamanızı sınırlandıran bir söz vermelisiniz?
Bunların her ikisi de aynı işlevin mükemmel geçerli uygulamalarıdır, ancak yaptığınız tek şey gereksiz yere bir elinizin arkasına bağlanmıştır.
Dahası, kolayca (ve yasal olarak atlatılmış) çok sığ bir vaattir.
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);
}
Bakın, sadece bir sarmalayıcı işlevini kullanmamaya söz vermiş olsam da bu şekilde uyguladım. Kötü adam bir filmdeki birini öldürmemeye söz verdiği ve onun adamına onları öldürmesini emrettiği zamanki gibi.
Bu gereksiz yapılar, kötü adam filminden bir vaatten daha değerli değildir.
Ancak yalan söyleme yeteneği daha da kötüleşir:
Ben sahte const kullanarak üstbilgi (bildirim) ve kod (tanım) const uyumsuz aydınlandı. Const-happy savunucuları bunun iyi bir şey olduğunu iddia ediyor çünkü const'u sadece tanımına koymanıza izin veriyor.
// Example of const only in definition, not declaration
class foo { void test(int *pi); };
void foo::test(int * const pi) { }
Ancak, tersi doğrudur ... sadece beyanda sahte bir sabit koyabilir ve tanımda görmezden gelebilirsiniz. Bu, bir API'daki gereksiz konstrüksiyonu daha korkunç bir şey ve korkunç bir yalan haline getirir - bu örneğe bakın:
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
}
Gereksiz tüm yapı, değişkeni değiştirmek veya değişkeni sabit olmayan referansla geçirmek istediğinde, başka bir yerel kopyayı veya bir sarmalayıcı işlevini kullanmaya zorlayarak uygulayıcının kodunu daha az okunabilir hale getirmektir.
Bu örneğe bakın. Hangisi daha okunabilir? İkinci fonksiyondaki ekstra değişkenin tek sebebinin, bazı API tasarımcılarının gereksiz bir yapıya atması olduğu açık mı?
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;
}
}
İnşallah burada bir şeyler öğrendik. Gereksiz yapı, bir API-dağınıklık gözü, sinir bozucu bir nag, sığ ve anlamsız bir vaat, gereksiz bir engeldir ve bazen çok tehlikeli hatalara yol açar.