Programing

i = i ++ + 1;

lottogame 2020. 5. 21. 08:02
반응형

i = i ++ + 1; C ++ 17에서 합법적입니까?


정의되지 않은 동작을 시작하기 전에 N4659 (C ++ 17)에 명시 적으로 나열되어 있습니다.

  i = i++ + 1;        // the value of i is incremented

그러나 N3337 (C ++ 11)

  i = i++ + 1;        // the behavior is undefined

무엇이 바뀌 었습니까?

내가 수집 할 수있는 것, [N4659 basic.exec]

언급 된 경우를 제외하고 개별 연산자의 피연산자 및 개별 표현식의 하위 표현식에 대한 평가는 순서가 없습니다. [...] 연산자의 피연산자의 값 계산은 연산자 결과의 값 계산 전에 시퀀싱됩니다. 메모리 위치에 대한 부작용이 동일한 메모리 위치에있는 다른 부작용 또는 동일한 메모리 위치에있는 객체의 값을 사용한 값 계산과 관련하여 순서가없고 잠재적으로 동시 적이 지 않은 경우에는 동작이 정의되지 않습니다.

여기서 [N4659 basic.type]에 정의되어 있습니다 .

사소 복사 가능한 유형의 값의 표현은 결정 객체 표현의 비트 세트 인 값을 값의 구현 된 집합의 하나 개의 개별 요소,

가입일 [basic.exec N3337]

언급 된 경우를 제외하고 개별 연산자의 피연산자 및 개별 표현식의 하위 표현식에 대한 평가는 순서가 없습니다. [...] 연산자의 피연산자의 값 계산은 연산자 결과의 값 계산 전에 시퀀싱됩니다. 스칼라 오브젝트의 부작용이 동일한 스칼라 오브젝트의 다른 부작용이나 동일한 스칼라 오브젝트의 값을 사용한 값 계산과 관련하여 순서가 지정되지 않은 경우, 동작은 정의되지 않습니다.

마찬가지로, 값은 [N3337 basic.type]에 정의되어 있습니다 .

사소하게 복사 가능한 유형의 경우, 값 표현은 구현을 정의한 값 세트 중 하나의 개별 요소 인 value 를 결정하는 오브젝트 표현의 비트 세트입니다.

중요하지 않은 동시성을 언급하고 스칼라 객체 대신 메모리 위치사용한다는 점을 제외하고는 동일 합니다 .

이러한 유형의 산술 유형, 열거 유형, 포인터 유형, 멤버 유형에 대한 포인터 std::nullptr_t및 cv 규정 버전을 통칭하여 스칼라 유형이라고합니다.

예제에 영향을 미치지 않습니다.

가입일 [expr.ass N4659]

대입 연산자 (=)와 복합 대입 연산자는 모두 오른쪽에서 왼쪽으로 그룹화됩니다. 모두 왼쪽 피연산자로 수정 가능한 lvalue가 필요하고 왼쪽 피연산자를 참조하는 lvalue를 반환합니다. 왼쪽 피연산자가 비트 필드 인 경우 모든 결과는 비트 필드입니다. 모든 경우에, 할당은 오른쪽과 왼쪽 피연산자의 값 계산 후와 할당 식의 값 계산 전에 순서화됩니다. 오른쪽 피연산자는 왼쪽 피연산자보다 먼저 시퀀싱됩니다.

가입일 [expr.ass N3337]

대입 연산자 (=)와 복합 대입 연산자는 모두 오른쪽에서 왼쪽으로 그룹화됩니다. 모두 왼쪽 피연산자로 수정 가능한 lvalue가 필요하고 왼쪽 피연산자를 참조하는 lvalue를 반환합니다. 왼쪽 피연산자가 비트 필드 인 경우 모든 결과는 비트 필드입니다. 모든 경우에, 할당은 오른쪽과 왼쪽 피연산자의 값 계산 후와 할당 식의 값 계산 전에 순서화됩니다.

유일한 차이점은 N3337에 마지막 문장이 없다는 것입니다.

그러나 왼쪽 피연산자 iid-expression 이 lvalue 인 것처럼 "다른 부작용" 이나 "같은 스칼라 오브젝트의 값 사용 " 이 아니므로 마지막 문장은 중요하지 않습니다 .


C ++ 11에서 "할당"행위, 즉 LHS 수정의 부작용 은 오른쪽 피연산자 값 계산 후에 시퀀싱 됩니다. 이는 상대적으로 "약한"보증 입니다. RHS의 값 계산 과 관련하여 만 시퀀싱을 생성합니다 . 부작용의 발생은 가치 계산의 일부가 아니기 때문에 RHS에 존재할 수있는 부작용 에 대해서는 아무 것도 언급 하지 않습니다 . C ++ 11의 요구 사항은 할당 행위와 RHS의 부작용 사이에 상대적인 시퀀싱을 확립하지 않는다. 이것이 UB의 잠재력을 창출하는 것입니다.

이 경우 유일한 희망은 RHS에 사용되는 특정 운영자가 수행 한 추가 보증입니다. RHS가 prefix를 사용한 경우 ++접두사 형식의 고유 한 시퀀싱 속성 ++이이 예에서 날짜를 저장했을 것입니다. 그러나 postfix ++는 다른 이야기입니다 : 그것은 그런 보장을하지 않습니다. C ++ 11 에서이 예제에서 부작용 =과 postfix의 부작용은 ++서로 관련이없는 순서로 끝납니다. 그리고 그것은 UB입니다.

C ++ 17에서는 할당 연산자의 사양에 추가 문장이 추가되었습니다.

오른쪽 피연산자는 왼쪽 피연산자보다 먼저 시퀀싱됩니다.

위와 함께 사용하면 매우 강력합니다. LHS에서 발생하는 모든보다 RHS에서 발생하는 모든 것 (모든 부작용 포함)을 순서대로 나열 합니다. 실제 할당은 LHS (및 RHS) 후에 시퀀싱되므로, 추가 시퀀싱은 RHS에 존재하는 부작용으로부터 할당 행위를 완전히 분리시킵니다. 이 강력한 시퀀싱은 위의 UB를 제거하는 것입니다.

(@John Bollinger의 의견을 고려하여 업데이트되었습니다.)


당신은 새로운 문장을 식별

오른쪽 피연산자는 왼쪽 피연산자보다 먼저 시퀀싱됩니다.

왼쪽 피연산자의 lvalue 로의 평가가 관련이 없음을 올바르게 식별했습니다. 그러나 시퀀싱 된 이전 은 전이 관계로 지정됩니다. 따라서 전체 오른쪽 피연산자 (사후 증가 포함) 할당 전에 순서화됩니다. C ++ 11에서는 할당 전에 올바른 피연산자 값 계산시퀀싱되었습니다.


이전 C ++ 표준 및 C11에서 대입 연산자 텍스트 정의는 다음 텍스트로 끝납니다.

피연산자의 평가는 순서가 없습니다.

피연산자의 부작용은 순서가 없으므로 동일한 변수를 사용하는 경우 확실히 정의되지 않은 동작입니다.

이 텍스트는 C ++ 11에서 간단하게 제거되어 다소 모호합니다. UB입니까, 그렇지 않습니까? 이것은 C ++ 17에서 다음과 같이 추가되었습니다.

오른쪽 피연산자는 왼쪽 피연산자보다 먼저 시퀀싱됩니다.


참고로, 이전 표준에서도 C99의 예는 매우 명확했습니다.

피연산자의 평가 순서는 지정되어 있지 않습니다. 할당 연산자의 결과를 수정하거나 다음 시퀀스 포인트 이후에 액세스하려고하면 동작이 정의되지 않습니다.

기본적으로 C11 / C ++ 11에서는이 텍스트를 제거 할 때 엉망이되었습니다.

참고 URL : https://stackoverflow.com/questions/47702220/what-made-ii-1-legal-in-c17

반응형