대답은 컴파일하는 C ++ 표준에 따라 다릅니다. 모든 코드는 다음 줄을 제외하고 모든 표준에서 완벽하게 잘 구성되어 있습니다 ‡ :
char * s = "My String";
이제 문자열 리터럴에는 유형이 const char[10]있으며 상수가 아닌 포인터를 초기화하려고합니다. char문자열 리터럴 계열을 제외한 다른 모든 유형의 경우 이러한 초기화는 항상 불법이었습니다. 예를 들면 :
const int arr[] = {1};
int *p = arr; // nope!
그러나 C ++ 11 이전 버전에서는 문자열 리터럴의 경우 §4.2 / 2에 예외가있었습니다.
와이드 문자열 리터럴이 아닌 문자열 리터럴 (2.13.4)은 " pointer to char " 유형의 rvalue로 변환 될 수 있습니다 . [...]. 두 경우 모두 결과는 배열의 첫 번째 요소에 대한 포인터입니다. 이 변환은 명시 적으로 적절한 포인터 대상 유형이있는 경우에만 고려되며 lvalue에서 rvalue로 일반적으로 변환해야하는 경우에는 고려되지 않습니다. [참고 : 이 변환은 더 이상 사용되지 않습니다 . 부록 D를 참조하십시오. ]
따라서 C ++ 03에서 코드는 더 이상 사용되지 않지만 명확하고 예측 가능한 동작을 가지고 있습니다.
C ++ 11에서는 해당 블록이 존재하지 않습니다.으로 변환 된 문자열 리터럴에 대한 예외가 없으므로 방금 제공 char*한 int*예제 처럼 코드 형식이 잘못되었습니다 . 컴파일러는 진단을 내릴 의무가 있으며, 이상적으로 이와 같은 경우 C ++ 유형 시스템에 대한 명확한 위반 인 경우, 좋은 컴파일러가이 점을 준수 할뿐 아니라 (예 : 경고를 발행하여) 실패 할 것으로 기대합니다. 노골적인.
코드는 이상적으로 컴파일되지 않아야합니다. 그러나 gcc와 clang 모두에서 수행됩니다 (이 유형 시스템 구멍이 10 년 넘게 사용되지 않음에도 불구하고 거의 이득없이 깨질 수있는 코드가 많기 때문이라고 가정합니다). 코드의 형식이 잘못되었으므로 코드의 동작이 무엇인지 추론하는 것은 의미가 없습니다. 그러나이 특정 사례와 이전에 허용 된 이력을 고려할 때 결과 코드를 const_cast다음과 같이 암시적인 것처럼 해석하는 것이 비합리적인 확장이라고 생각하지 않습니다 .
const int arr[] = {1};
int *p = const_cast<int*>(arr); // OK, technically
그것으로, 당신이 실제로 s다시 는 만지지 않기 때문에 나머지 프로그램은 완벽하게 괜찮 습니다. 읽기 created- const비를 통해 객체를 const포인터 것은 무방하다. 이러한 포인터를 통해 생성 된 객체를 작성 하는 const것은 정의되지 않은 동작입니다.
std::cout << *p; // fine, prints 1
*p = 5; // will compile, but undefined behavior, which
// certainly qualifies as "unpredictable"
s코드의 어느 곳에서나 수정이 없기 때문에 프로그램은 C ++ 03에서는 괜찮습니다. C ++ 11에서는 컴파일에 실패해야하지만 어쨌든 수행합니다. 컴파일러에서 허용하는 경우에도 정의되지 않은 동작은 없습니다 † . 컴파일러가 여전히 C ++ 03 규칙을 [잘못] 해석하고 있다는 점을 감안하면 "예측할 수없는"동작으로 이어질 수있는 것은 없습니다. 글을 쓰면 s모든 베팅이 해제됩니다. C ++ 03 및 C ++ 11 모두에서.
† 다시 말하지만, 정의상 잘못된 형식의 코드는 합리적인 동작을 기대
하지 않습니다. ‡ 그렇지 않은 경우를 제외하고 Matt McNabb의 답변을 참조하십시오.