C ++ 11에 void 포인터 비교에 대한 이상한 절이 포함 된 이유는 무엇입니까?
다른 질문에 대한 참조를 확인하는 동안 C ++ 11에서 [expr.rel] ¶3에서 이상한 절을 발견했습니다.
포인터
void
로 정의 된 결과와 비교 될 수있다 (포인터 변환 후)은 다음과 같다 : 두 포인터는 동일한 주소를 나타내고 또는 모두 널 포인터 값이 있다면, 결과가true
조작자인지<=
또는>=
과false
그렇지 그렇지 않으면 결과가 지정되지 않습니다.
이것은 두 개의 포인터가 캐스트되면 void *
순서 관계가 더 이상 보장되지 않음 을 의미하는 것 같습니다 . 예를 들면 다음과 같습니다.
int foo[] = {1, 2, 3, 4, 5};
void *a = &foo[0];
void *b = &foo[1];
std::cout<<(a < b);
지정되지 않은 것 같습니다.
흥미롭게도이 절은 C ++ 03에는없고 C ++ 14에서는 사라졌습니다. 따라서 위의 예를 들어 C ++ 14 단어를 적용하면 ¶3.1
- 두 포인터가 동일한 배열의 다른 요소 또는 하위 객체를 가리키는 경우 더 높은 첨자를 가진 요소에 대한 포인터가 더 크게 비교됩니다.
로 적용 할 a
과 b
그들이에 주조 된 경우에도, 점 같은 배열의 요소 void *
. ¶3.1의 표현은 C ++ 11에서도 거의 동일하지만 void *
절에 의해 무시 된 것처럼 보였습니다 .
내 이해가 옳은가? C ++ 11에서 추가되고 즉시 제거 된 이상한 절의 요점은 무엇입니까? 아니면 아직 거기에 있지만 표준의 다른 부분으로 옮겨 졌거나 암시 되었습니까?
TL; DR :
- C ++ 98 / 03에서는이 절이 존재하지 않았고 표준은
void
포인터 에 대한 관계 연산자를 지정하지 않았습니다 (핵심 문제 879,이 게시물 끝 참조). void
포인터 비교에 대한 이상한 절이 이를 해결하기 위해 C ++ 11에 추가되었지만 이로 인해 다른 두 가지 핵심 문제 583 및 1512가 발생했습니다 (아래 참조).- 이러한 문제를 해결하려면 절을 제거하고 C ++ 14 표준에있는 문구로 교체해야하므로 "정상"
void *
비교가 가능합니다.
핵심 문제 583 : 널 포인터 상수에 대한 관계형 포인터 비교
- 널 포인터 상수에 대한 관계형 포인터 비교 섹션 : 8.9 [expr.rel]
C에서는 형식이 잘못되었습니다 (C99 6.5.8 참조).
void f(char* s) { if (s < 0) { } } ...but in C++, it's not. Why? Who would ever need to write (s > 0) when they could just as well write (s != 0)?
이것은 ARM (그리고 아마도 그 이전) 이후의 언어로되어 있습니다. 피연산자 중 하나가 포인터 유형일 때마다 두 피연산자 모두에서 포인터 변환 (7.11 [conv.ptr])을 수행해야하기 때문입니다. 따라서 "null-ptr-to-real-pointer-type"변환이 다른 포인터 변환과 함께 타는 것처럼 보입니다.
제안 된 결의안 (2013 년 4 월) :
이 문제는 문제 1512 의 해결로 해결되었습니다 .
핵심 이슈 1512 : 포인터 비교 vs 자격 변환
- 포인터 비교 vs 자격 변환 섹션 : 8.9 [expr.rel]
8.9 [expr.rel] 단락 2에 따르면 포인터 비교를 설명합니다.
포인터 변환 (7.11 [conv.ptr]) 및 제한 변환 (7.5 [conv.qual])은 포인터 피연산자 (또는 포인터 피연산자 및 널 포인터 상수 또는 두 개의 널 포인터 상수에 대해 수행됩니다. 정수가 아님)을 복합 포인터 유형으로 가져옵니다. 이로 인해 다음 예제가 잘못된 것으로 보입니다.
bool foo(int** x, const int** y) { return x < y; // valid ? } because int** cannot be converted to const int**, according to the rules of 7.5 [conv.qual] paragraph 4.
이것은 포인터 비교에 너무 엄격 해 보이며 현재 구현에서는 예제를 받아들입니다.
제안 된 결의안 (2012 년 11 월) :
위의 문제 해결 에서 발췌 한 관련 내용은 다음 논문에서 찾을 수 있습니다. 포인터 비교 대 자격 변환 (개정판 3) .
다음은 핵심 문제 583 도 해결합니다 .
5.9 expr.rel 단락 1에서 5로 변경 :
이 섹션에서는 다음 문 ( C ++ 11 의 odd 절 )이 삭제 되었습니다 .
포인터
void
로 정의 된 결과와 비교 될 수있다 (포인터 변환 후)은 다음과 같다 : 두 포인터는 동일한 주소를 나타내고 또는 모두 널 포인터 값이 있다면, 결과가true
조작자인지<=
또는>=
과false
그렇지 그렇지 않으면 결과가 지정되지 않습니다.
그리고 다음 문장이 추가되었습니다 .
- 두 포인터가 동일한 배열의 다른 요소 또는 하위 객체를 가리키는 경우 더 높은 첨자를 가진 요소에 대한 포인터가 더 크게 비교됩니다.
- 하나의 포인터가 배열의 요소 또는 하위 객체를 가리키고 다른 포인터가 배열의 마지막 요소를 지나서 가리키면 후자의 포인터가 더 크게 비교됩니다.
따라서 C ++ 14 (n4140) 섹션 [expr.rel] / 3 의 최종 작업 초안 에서 위의 진술은 해결 시점에 언급 된대로 발견됩니다.
이 이상한 절이 추가 된 이유를 파헤 치면 훨씬 더 이른 문제인 879 : Missing built-in comparison operator for pointer types . 이 문제에 대한 제안 된 해결책 (2009 년 7 월)에 따라 2009 년 10 월 WP에 투표 된이 조항이 추가되었습니다.
이것이 C ++ 11 표준에 포함 된 방법입니다.
'code' 카테고리의 다른 글
IntelliJ를 사용하여 두 개의 임의 파일 비교 (0) | 2020.12.14 |
---|---|
#temptable과 ## TempTable의 차이점은 무엇입니까? (0) | 2020.12.13 |
ReSharper 7.x를 VS2013 미리보기와 함께 사용할 수 있습니까? (0) | 2020.12.13 |
Eclipse가 Visual Studio처럼 동작하도록 만들기 (0) | 2020.12.13 |
async / await를 사용하여 WCF 서비스를 호출하기위한 패턴 (0) | 2020.12.13 |