이 프로그램의 출력 :
#include <iostream>
class c1
{
public:
c1& meth1(int* ar) {
std::cout << "method 1" << std::endl;
*ar = 1;
return *this;
}
void meth2(int ar)
{
std::cout << "method 2:"<< ar << std::endl;
}
};
int main()
{
c1 c;
int nu = 0;
c.meth1(&nu).meth2(nu);
}
Is :
method 1
method 2:0
시작할 nu
때 1 이 아닌 이유는 무엇 meth2()
입니까?
답변
평가 순서가 지정되지 않았기 때문입니다.
당신은 전에 평가받는 것을보고 있습니다 nu
.main
0
meth1
호출된다. 이것이 연결 문제입니다. 하지 않는 것이 좋습니다.
멋지고 간단하고 명확하고 읽기 쉽고 이해하기 쉬운 프로그램을 만드십시오.
int main()
{
c1 c;
int nu = 0;
c.meth1(&nu);
c.meth2(nu);
}
답변
평가 순서에 관한 표준 초안 의이 부분 이 적절 하다고 생각합니다 .
1.9 프로그램 실행
…
- 언급 된 경우를 제외하고 개별 연산자의 피연산자 및 개별 식의 하위 식에 대한 평가는 순서가 지정되지 않습니다. 연산자의 피연산자의 값 계산은 연산자 결과의 값 계산 전에 순서가 지정됩니다. 스칼라 객체에 대한 부작용이 동일한 스칼라 객체에 대한 다른 부작용 또는 동일한 스칼라 객체의 값을 사용하는 값 계산과 관련하여 순서가 지정되지 않고 잠재적으로 동시 적이 지 않은 경우 동작이 정의되지 않습니다.
그리고 또한:
5.2.2 함수 호출
…
- [참고 : 접미사 식과 인수의 평가는 모두 서로에 대해 순서가 지정되지 않습니다. 인수 평가의 모든 부작용은 함수가 입력되기 전에 순서가 지정됩니다 — 끝 참고]
따라서 라인의 c.meth1(&nu).meth2(nu);
경우 최종 호출에 대한 함수 호출 연산자의 관점에서 연산자에서 무슨 일이 발생하는지 고려 meth2
하여 접미사 표현식과 인수로의 분석을 명확하게 볼 수 있습니다 nu
.
operator()(c.meth1(&nu).meth2, nu);
최종 함수 호출 (즉, 후위 식 및 ) 에 대한 후위 식 및 인수 의 평가는 위 의 함수 호출 규칙에 따라 서로에 대해 순서 가 지정 되지 않습니다 . 따라서 스칼라 객체에 대한 접미사 표현식 계산의 부작용 은 함수 호출 이전 의 인수 평가와 관련하여 순서가 지정되지 않습니다. 위 의 프로그램 실행 규칙에 따르면 이것은 정의되지 않은 동작입니다.c.meth1(&nu).meth2
nu
ar
nu
meth2
즉, 컴파일러가 호출 후 호출에 대한 nu
인수 를 평가할 필요가 없습니다. 즉, meth2
호출 meth1
에 영향을 meth1
미치는 부작용이 없다고 가정 할 수 있습니다 .nu
. 평가에 .
위에서 생성 된 어셈블리 코드는 main
함수에 다음 시퀀스를 포함합니다 .
- 변하기 쉬운
nu
는 스택에 할당되고 0으로 초기화됩니다. - 레지스터 (
ebx
제 경우)는 다음 값의 사본을받습니다.nu
- 의 주소
nu
및c
매개 변수 레지스터에로드됩니다. meth1
불린다- 반환 값 레지스터와 이전에 캐시 된 값 의
nu
에서ebx
레지스터 파라미터 레지스터에로드 meth2
불린다
중요하게도 위의 5 단계에서 컴파일러는 nu
2 단계 의 캐시 된 값을 에 대한 함수 호출에서 재사용 할 수 있습니다 meth2
. 여기서는 작동중인 ‘정의되지 않은 동작’ nu
호출에 의해 변경되었을 수 있는 가능성을 무시합니다 meth1
.
참고 : 이 답변은 원래 형식에서 실질적으로 변경되었습니다. 마지막 함수 호출 전에 순서가 지정되지 않은 피연산자 계산의 부작용에 대한 초기 설명은 정확하지 않기 때문입니다. 문제는 피연산자 자체의 계산이 불확실하게 배열된다는 사실입니다.
답변
1998 년 C ++ 표준, 섹션 5, para 4
언급 된 경우를 제외하고 개별 연산자의 피연산자 및 개별 식의 하위 식에 대한 평가 순서와 부작용이 발생하는 순서는 지정되지 않습니다. 이전 시퀀스 포인트와 다음 시퀀스 포인트 사이에서 스칼라 객체는 표현식 평가에 의해 최대 한 번 수정 된 저장된 값을 가져야합니다. 또한 이전 값은 저장할 값을 결정하기 위해서만 액세스해야합니다. 이 단락의 요구 사항은 전체 표현의 하위 표현의 허용 가능한 각 순서에 대해 충족되어야합니다. 그렇지 않으면 동작이 정의되지 않습니다.
(이 질문과 관련이없는 각주 # 53에 대한 참조는 생략했습니다.)
기본적으로 &nu
호출하기 전에 평가해야 c1::meth1()
하고, nu
호출하기 전에 평가되어야한다 c1::meth2()
. 그러나 nu
이전에 평가해야하는 요구 사항은 없습니다 &nu
(예 : nu
먼저 평가 &nu
한 c1::meth1()
다음를 호출 한 다음 호출 하는 것이 허용됩니다. 이것이 컴파일러가 수행하는 작업 일 수 있음). 표현 *ar = 1
에 c1::meth1()
따라서 이전에 평가되는 것은 아닙니다 nu
인은 main()
에 전달하기 위해, 평가c1::meth2()
.
이후의 C ++ 표준 (현재 내가 오늘 밤 사용하는 PC에는없는)은 본질적으로 동일한 절을 가지고 있습니다.
답변
컴파일 할 때 meth1 및 meth2 함수가 실제로 호출되기 전에 매개 변수가 전달되었다고 생각합니다. “c.meth1 (& nu) .meth2 (nu);”를 사용할 때 nu = 0 값이 meth2에 전달되었으므로 “nu”가 후자 변경 되더라도 상관 없습니다.
당신은 이것을 시도 할 수 있습니다 :
#include <iostream>
class c1
{
public:
c1& meth1(int* ar) {
std::cout << "method 1" << std::endl;
*ar = 1;
return *this;
}
void meth2(int* ar)
{
std::cout << "method 2:" << *ar << std::endl;
}
};
int main()
{
c1 c;
int nu = 0;
c.meth1(&nu).meth2(&nu);
getchar();
}
그것은 당신이 원하는 답을 얻을 것입니다