여분의 불필요한 const는 API 관점에서 좋지 않습니다.
값에 의해 전달되는 내장형 매개 변수에 대해 불필요한 불필요한 const를 코드에 넣으면 API가 복잡해 지지만 호출자 또는 API 사용자에게 의미있는 약속은하지 않습니다 (구현을 방해 할뿐).
필요하지 않을 때 API에서 너무 많은 'const'는 " 울음 울음 소리 "와 같 으며, 결국 사람들은 'const'를 무시하기 시작합니다. 왜냐하면 그것이 어디에나 있고 대부분의 시간을 의미하지 않기 때문입니다.
API의 추가 const에 대한 "reductio ad absurdum"인수는 처음 두 가지 점에서 유용합니다. 더 많은 const 매개 변수가 좋으면 const를 가질 수있는 모든 인수는 const가 있어야합니다. 사실, 그것이 정말로 좋으면 const가 매개 변수의 기본값이되고 매개 변수를 변경하려는 경우에만 "mutable"과 같은 키워드를 원할 것입니다.
우리가 할 수있는 곳에 const를 입력 해 봅시다 :
void mungerum(char * buffer, const char * mask, int count);
void mungerum(char * const buffer, const char * const mask, const int count);
위의 코드 줄을 고려하십시오. 선언은 더 복잡하고 읽기가 길고 읽기 어려울뿐만 아니라 4 개의 'const'키워드 중 3 개를 API 사용자가 안전하게 무시할 수 있습니다. 그러나 'const'를 추가로 사용하면 두 번째 줄이 위험 할 수 있습니다!
왜?
첫 번째 매개 변수를 빨리 읽지 char * const buffer
않으면 전달 된 데이터 버퍼의 메모리가 수정되지 않는다고 생각할 수 있지만 이는 사실이 아닙니다! 불필요한 'const'는 스캔하거나 빠르게 읽을 때 API에 대한 위험하고 잘못된 가정을 초래할 수 있습니다 .
불필요한 const는 코드 구현 관점에서도 좋지 않습니다.
#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이 true가 아닌 경우, API는 아래 첫 번째 방법으로 함수를 구현하지 않을 것으로 "약속"합니다.
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];
}
}
그것은 매우 어리석은 약속입니다. 발신자에게 전혀 혜택을주지 않고 구현을 제한하는 약속을해야하는 이유는 무엇입니까?
두 가지 모두 동일한 기능을 완벽하게 유효하게 구현 한 것이므로 수행 한 모든 작업은 불필요하게 한 손으로 등 뒤로 묶여 있습니다.
게다가, 그것은 쉽게 (그리고 법적으로 우회되는) 매우 얕은 약속입니다.
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);
}
랩퍼 함수를 사용하지 않겠다고 약속했지만 어쨌든 그렇게 구현했습니다. 나쁜 사람이 영화에서 누군가를 죽이지 않겠다고 약속하고 대신에 그를 대신 해달라고 명령하는 것과 같습니다.
그 불필요 한 const는 영화 나쁜 사람의 약속보다 더 가치가 없습니다.
그러나 거짓말하는 능력은 더욱 악화됩니다.
가짜 const를 사용하여 헤더 (선언)와 코드 (정의)의 const를 불일치 할 수 있음을 깨달았습니다. const-happy 옹호자들은 const를 정의에만 넣을 수 있기 때문에 이것이 좋은 것이라고 주장합니다.
// Example of const only in definition, not declaration
class foo { void test(int *pi); };
void foo::test(int * const pi) { }
그러나 그 반대는 사실입니다 ... 당신은 선언에만 가짜 const를 넣고 정의에서 무시할 수 있습니다. 이것은 API의 불필요한 const를 끔찍한 짓과 끔찍한 거짓말로 만듭니다.이 예제를보십시오.
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
}
불필요한 불필요한 const는 실제로 변수를 변경하거나 비 const 참조로 변수를 전달하려고 할 때 다른 로컬 사본 또는 래퍼 함수를 사용하도록 강제함으로써 구현 자의 코드를 읽기 어렵게 만듭니다.
이 예를보십시오. 더 읽기 쉬운 것은 무엇입니까? 두 번째 함수의 추가 변수에 대한 유일한 이유는 일부 API 디자이너가 불필요한 const를 던 졌기 때문입니까?
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;
}
}
잘만되면 우리는 여기에서 무언가를 배웠다. 불필요한 const는 API 혼란스러운 눈가리개, 성가신 잔소리, 얕고 의미없는 약속, 불필요한 방해이며 때로는 매우 위험한 실수로 이어집니다.