C++에는 (아마도 유일한) 묵시적 const_cast 가 있다. 바로,
char* str = “hello, world”;
이건 C++이 (최대한) C와의 하위 호환성을 가지려다 보니 나온 문제다. C 표준 라이브러리의 수많은 문자열 처리 함수들이 char* 을 인자로 받긴하지만, 의미 상으론 const char* 인 경우가 대부분이기 때문;
만약 const char* –> char* 을 명시적으로 바꿔야 한다면 많은 수의 C 코드가 C++ 컴파일러에서 컴파일되지 않게 된다. 그래서 이건 묵시적으로 const_cast<char*> 을 해 버린다.
하지만 모든 C 문자열 처리 함수가 const char* 의 의미로 동작하는건 아니다. 그래서 예전 버전의 Mozilla 에선 이와 관련한 버그가 있었다. 공유 문자열 버퍼를 strchr 같이 실제로 버퍼를 조작하는 함수에서 문제가 생기는 것 – const semantic이 깨지는 것.
여튼 지금 문제는 이게 아니라(…), 오전에 everclear 군이 제기한 코드;
아래와 같은 코드가 있다. 왜 성공적으로 컴파일 될까?
struct A {
int& a;
explicit A(int& _a) : a(_a) { }
A(const A& rhs) : a(rhs.a) { }
};
int& a;
explicit A(int& _a) : a(_a) { }
A(const A& rhs) : a(rhs.a) { }
};
const A&인 rhs.a 는 const int& 가 되야 하지 않나? 비슷하게 int& a 대신 int* const a 여도 저 코드는 잘 동작한다; 대체 왜 이럴까?
테스트 해 보니 struct의 const는 struct 자체가 const이지 내용까지 const가 되는 것은 아닌 것 같음.
int* const a 경우는 const 대상이 value가 아니라 address라서 상관 없는 것 같고 const int* a로 하면 안될 듯?
전 rhs.a 가 int* const 일 때도 const int* const 가 될 꺼라고 생각했죠(…). 형 말대로 address라 그런 듯
C++의 const는 해당 객체나 배열이 “실제로” 차지하는 메모리 영역에 대한 비트 수준의 상수성만을 보장하는 것으로 알고 있습니다. 저 경우는 참조만 가져오는 것은 실제 포인터만 복사하이니 입력 인자로 주어진 객체의 비트 수준 상수성을 깨지 않기 때문에 허용되는 것 같고요. 그래서 포인터나 참조에 대한 상수성을 보장하려면 const getter 함수를 만들어야 하죠 OTL
그 말 그대로인듯합니다 OTL
읽으면서 자문 이후에 답을 쓰는 형식을 기대하면서 내렸는데
자문으로 마무리 되는 포스팅이네요 ㅋㅋㅋ
…앞 부분은 질문을 하기 위한 프롤로그지(???)
struct const의 멤버변수들은 const가 되지 않습니다. 위의 struct A로 예로 들면
int a = 3;
const A foo(a);
foo.a = 4;
위의 코드는 문제없이 작동합니다. foo는 상수지만, foo.a는 상수가 아니기 때문이죠.
그래서 A(const A& rhs) : a(rhs.a) { } rhs.a가 상수가 아니기 때문에 컴파일이 됩니다.
struct const 의 말이 잘 이해가 안가긴하는데, summerlight 님과 같은 의미인건가요?
A* const 같은 의미라면 말이 되는데, 단순히 const 인 구조체의 멤버는 const는 아니란 말인지 좀 모호하네요;
만약 제가 잘못 이해한거라면;
struct A {
int x;
};
const A a;
a.x = 0; // error
const struct 의 멤버들은 const 라 (summerlight 님의 말대로 메모리 레벨에서), 코드가 컴파일 되지 않습니다.
http://pastebin.com/0KpkDS8c
위와 같은 코드도 돌아가는 걸로 봐서는…
rhs.a 가 int& 인것 같아요
흠…저 코드만으론 verify되지 않는듯
헉..
어떤 const 객체의 멤버 중에 레퍼런스가 있을 때, const 임에도 불구하고 그 멤버를 마음대로 바꿀 수 있는 건가요?? …
ㅇㅇ
그닥 deep casting 해주진 않는듯? 그래서 const & A 인 경우에는 A::do_somthing(..) const { … } 이건 호출 가능하고, A::do_something(..) { … } 이건 불가능하고 – 이런 제한이 붙는거 아닐까? 저렇게 깊게 const casting 해주면 이런거 필요 없을 것 같은데
네 그렇죠;
이런 이유 때문에 D(2.0기준)에는 const와 invariant를 구분하고 있지요.
D에선 그렇군요; 아예 이런걸 포기한 언어도 많은데(…) 왜 이렇게 어중간한지;;
C99 3.9.3.3에 이런 말이 있군요. Each non-static, non-mutable, non-reference data member of a const-qualified class object is const-qualified, .
static/mutable 멤버는 당연할텐데, reference가 그럴 거라고는 상상 못했네요.
summerlight 님 말과 같은 얘기가 되겠네요. 결국 C++이 만들어주는 상수성(const-ness)의 개념이 단순한 메모리 상수성이라 표준도 일단 저러한듯 하군요;
mutable은 변형이니 약간 다른 얘기지만요(…).