모두 (a)
와 (b)
정의되지 않은 동작이 발생할. 널 포인터를 통해 멤버 함수를 호출하는 것은 항상 정의되지 않은 동작입니다. 함수가 정적 인 경우 기술적으로도 정의되지 않지만 일부 분쟁이 있습니다.
가장 먼저 이해해야 할 것은 널 포인터를 역 참조하는 것이 정의되지 않은 동작 인 이유입니다. C ++ 03에서는 실제로 여기에 약간의 모호성이 있습니다.
비록 "정의되지 않은 동작에 널 포인터 결과를 역 참조" §1.9 / 4, §8.3.2 / 4 모두 노트에 언급, 그것은 명시 적으로 언급 한 적이 없어요. (참고는 비표준입니다.)
그러나 §3.10 / 2에서 추론 할 수 있습니다.
lvalue는 개체 또는 함수를 나타냅니다.
역 참조 할 때 결과는 lvalue입니다. 널 포인터 는 객체를 참조 lvalue를 사용할 때 정의되지 않은 동작이 있습니다. 문제는 이전 문장이 결코 언급되지 않았다는 것입니다. 그래서 lvalue를 "사용"한다는 것은 무엇을 의미합니까? 아예 생성하거나 lvalue에서 rvalue로 변환하는보다 형식적인 의미에서 사용 하시겠습니까?
어쨌든 rvalue (§4.1 / 1)로 변환 할 수는 없습니다.
lvalue가 참조하는 객체가 T 유형의 객체가 아니고 T에서 파생 된 유형의 객체가 아니거나 객체가 초기화되지 않은 경우이 변환을 필요로하는 프로그램은 정의되지 않은 동작을 갖습니다.
여기에는 확실히 정의되지 않은 동작이 있습니다.
모호성은 정의되지 않은 동작인지 여부에서 비롯 되지만 유효하지 않은 포인터의 값을 사용 하지 않습니다 (즉, lvalue를 가져 오지만 rvalue로 변환하지 않음). 그렇지 않다면 int *i = 0; *i; &(*i);
잘 정의되어 있습니다. 이것은 활발한 문제 입니다.
따라서 우리는 엄격한 "널 포인터 역 참조, 정의되지 않은 동작 가져 오기"뷰와 약한 "비 참조 된 널 포인터 사용, 정의되지 않은 동작 얻기"뷰가 있습니다.
이제 우리는 질문을 고려합니다.
예, (a)
정의되지 않은 동작이 발생합니다. 사실 this
이 null이면 함수 의 내용에 관계없이 결과는 정의되지 않습니다.
이것은 §5.2.5 / 3에서 다음과 같습니다.
E1
"클래스 X에 대한 포인터"유형이있는 경우 표현식 E1->E2
은 동등한 형식으로 변환됩니다.(*(E1)).E2;
*(E1)
엄격한 해석으로 정의되지 않은 동작이 발생 .E2
하고 rvalue로 변환되어 약한 해석에 대해 정의되지 않은 동작이됩니다.
또한 (§9.3.1 / 1)에서 직접 정의되지 않은 동작입니다.
X 유형이 아니거나 X에서 파생 된 유형의 객체에 대해 클래스 X의 비 정적 멤버 함수가 호출되면 동작이 정의되지 않습니다.
정적 함수를 사용하면 엄격한 해석과 약한 해석이 차이를 만듭니다. 엄밀히 말하면 정의되지 않았습니다.
정적 멤버는 클래스 멤버 액세스 구문을 사용하여 참조 될 수 있으며,이 경우 object-expression이 평가됩니다.
즉, 정적이 아닌 것처럼 평가되고 다시 한 번 (*(E1)).E2
.
그러나 E1
정적 멤버 함수 호출에서 사용되지 않기 때문에 약한 해석을 사용하면 호출이 잘 정의됩니다. *(E1)
결과가 lvalue이고 정적 함수가 해결되고 *(E1)
삭제되고 함수가 호출됩니다. lvalue에서 rvalue 로의 변환이 없으므로 정의되지 않은 동작이 없습니다.
C ++ 0x에서는 n3126부터 모호성이 남아 있습니다. 지금은 안전합니다 : 엄격한 해석을 사용하십시오.