03.03 - 증감 연산자와 사이드 이펙트 (Increment/decrement operators, and side effects)
변수를 증가(+1)하고 감소(-1)하는 것은 흔한 연산이기 때문에 C++ 에는 전위(prefix) 버전과 후위(postfix) 버전 두 가지 연산이 있다.
Operator |
Symbol |
Form |
Operation |
Prefix increment (pre-increment) |
++ |
++x |
Increment x, then evaluate x |
Prefix decrement (pre-decrement) |
–– |
––x |
Decrement x, then evaluate x |
Postfix increment (post-increment) |
++ |
x++ |
Evaluate x, then increment x |
Postfix decrement (post-decrement) |
–– |
x–– |
Evaluate x, then decrement x |
전위 증감 연산자(prefix increment/decrement operator)는 매우 간단하다. 증가 또는 감소한 다음 x
값을 평가한다.
int x = 5;
int y = ++x;
후위 증감 연산자(postfix increment/decrement operator)는 조금 더 까다롭다. 컴파일러는 x
의 임시 복사본을 만들고, 원본 x
를 증가시키거나 감소시킨 다음 x
의 임시 복사본을 평가한다. 그다음 x
의 임시 복사본이 삭제된다.
int x = 5;
int y = x++;
위 코드가 어떻게 수행되는지 알아보자. 먼저, 컴파일러는 x
와 같은 값을 가진 임시 복사본 x(5)
를 만든다. 그런 다음 원본 x
를 5에서 6으로 증가시킨다. 그런 다음 컴파일러가 5로 평가되는 임시 복사본 x
값을 y
에 할당한다. 그런 다음 임시 복사본이 삭제된다.
결과적으로 x
는 값이 5이고, y
는 6이다.
다음은 전위 연산자와 후위 연산자의 차이를 보여주는 다른 예이다:
int x = 5, y = 5;
std::cout << x << " " << y << '\n';
std::cout << ++x << " " << --y << '\n';
std::cout << x << " " << y << '\n';
std::cout << x++ << " " << y-- << '\n';
std::cout << x << " " << y << '\n';
This produces the output:
5 5
6 4
6 4
6 4
7 3
세 번째 줄 std::cout << ++x << " " << --y << '\n';
에서 x
와 y
는 평가되기 전에 증가하고 감소하므로 새로운 값은 std::cout으로 출력된다.
다섯 번째 줄 std::cout << x++ << " " << y-- << '\n';
에서는 원래 값의 임시 복사본(x=6, y=4)
이 std::cout으로 전송된 다음 원래 x
와 y
가 증가한다. 그래서 다음 줄까지 후위 연산자의 결과가 보이지 않는다.
전위 증감 연산자를 사용하는 것이 후위 증감 연산자를 사용하는 것보다 성능이 더 좋을뿐더러 이상한 문제에 부딪힐 가능성이 더 작다.
사이드 이펙트 (Side effects)
'사이드 이펙트(side effect)'란 함수 또는 표현식이 특정 상태(Ex. 메모리에 저장된 정보)를 수정하거나 입력 또는 출력하거나 다른 함수를 호출하는 것을 말한다.
사이드 이펙트는 대부분 유용하다:
x = 5;
++x;
std::cout << x;
위 예제에서 할당 연산자(=
)는 x
의 값을 변경하는 사이드 이펙트를 가진다. 명령문이 실행 완료된 후에도 x
는 값이 5이다. 연산자 ++
는 x
값을 증가시키는 사이드 이펙트가 있다. x
의 출력은 콘솔을 수정하는 사이드 이펙트를 가진다.
그러나 사이드 이펙트는 예상치 못한 문제를 일으키기도 한다:
int add(int x, int y)
{
return x + y;
}
int main()
{
int x = 5;
int value = add(x, ++x);
std::cout << value;
return 0;
}
C++은 함수 인수를 평가하는 순서를 정의하지 않았다. 만약 왼쪽 인수를 먼저 평가하면 add(5, 6)
을 호출하여 11
을 반환하고, 오른쪽 인수를 먼저 평가하면 add(6, 6,)
이 되어 12
를 반환한다.
add()
함수에 대한 인수 중 하나가 사이드 이펙트를 가지고 있기므로 이런 문제가 생긴다.
undefined behavior:
int main()
{
int x = 1;
x = x++;
std::cout << x;
return 0;
}
정의되지 않은 동작(undefined behavior)이란 프로그래밍 언어에서 동작이 제대로 정의하지 않은 코드를 실행한 결과를 말한다.
할당 전에 ++
연산자가 먼저 적용되면 1
이 출력된다. (후위 연산자 ++
는 x
를 1에서 2로 증가시키지만 1로 평가되므로 표현식은 x = 1
이 된다. )
할당 후에 ++
연산자가 적용되면 2
가 출력된다. (x = x
로 평가한 다음 ++
를 적용하여 1에서 2로 x
가 증가한다.)
위와 같은 문제들은 사이드 이펙트가 적용된 변수를 한 명령문(statement)에서 두 번 이상 사용하지 않음으로써 모두 피할 수 있다.
이 포스트의 원문은 http://www.learncpp.com/cpp-tutorial/33-incrementdecrement-operators-and-side-effects/ 입니다.