이전 포스팅에서 C++의 value category(https://m42-orion.tistory.com/67)에 대해 알아보았다.
짧게 정리를 해보자.
C++ 11 이후의 value category를 구분하는 기준에는 identity와 move 두 가지가 있다.
identity는 두 객체(entity)의 주소(address)를 비교하여 두 객체가 같은지 확인할 수 있는지를 나타낸다.
move는 어떤 값이 다른 값으로 이동될 수 있음을 이야기한다.
구분 기준에 따라서 Mixed category(복합 카테고리)와 Primary category(기본 카테고리)로 나눌 수 있다.
먼저 Mixed category는 gl-value(i)과 r-value(m)로 나눌 수 있으며,
Primary category는 x-value(im), l-value(iM), pr-value(Im)으로 나눌 수 있다.
그런데 전위 연산자는 l-value에 속하는 반면, 후위 연산자는 r-value에 속한다.
똑같이 값을 1 올려주는 연산자인데 왜 하나는 l-value이고 하나는 r-value 일까?
그 이유는 전위 연산자와 후위 연산자의 동작 방식이 다르기 때문이다.
오늘은 이 내용에 대해서 다뤄보려고 한다.
⭐️전위 연산자와 후위 연산자
아주 간단하게 정리해보자.
전위 연산자와 후위 연산자 모두 피연산자의 값을 더하거나 빼는 단항 연산자이다.
전위 연산자의 경우 ++num과 같은 형태로 사용하며, num의 값을 1 증가시킨 후에 다른 작업을 진행한다.
후위 연산자의 경우 num++과 같은 형태로 사용하며, 전위 연산자와는 달리 값을 나중에 증가시킨다.
⭐️ 전위 연산자와 후위 연산자의 동작 방식의 차이
이제 전위 연산자와 후위 연산자의 차이를 알아보자.
두 단항 연산자 모두 피연산자의 값을 1 증가/감소 시키는 역할을 한다.
하지만 두 연산자의 작동 방식에 차이가 있어 다음과 같은 차이를 발생시키곤 한다.
int num = 10;
// 전위 연산자의 경우: compile error가 뜨지 않는다.
++num = 30;
// 후위 연산자의 경우: complile error! [error C2106: '=': 왼쪽 피연산자는 l-value이어야 합니다.]
num++ = 30;
오류 문구를 보면 num++은 l-value가 아니기 때문에 num++ = 30;이 컴파일 에러가 났음을 알 수 있다.
그렇다는 것은 전위 연산자는 l-value이고, 후위 연산자는 r-value라는 뜻인데, 왜 이런 차이가 날까?
전위 연산자 (prefix operator)
int num = 10;
++num = 30;
결론부터 말하자면, 전위 연산자의 경우 다른 수식을 계산하기 전에 먼저 값을 증가시키고, 그 결과를 객체로 반환한다.
천천히 과정을 살펴보면, 우선 num은 메모리 주소를 가지고 있는 변수이므로 l-value이다.
표현식(expression) ++num = 30을 실행한다고 하면, 우선 메모리에 있는 num 객체의 값을 직접 1 증가시킨다.
그리고 num 객체를 반환한다.
즉, 전위 연산자는 자기 객체를 반환하며, 이는 주소 값을 가지고 있다는 뜻이다.
그리고 이것은 주소 값을 통해 identity를 구분할 수 있다는 뜻이므로, l-value라고 볼 수 있다.
후위 연산자 (postfix operator)
int num = 10;
num++ = 30; // error
후위 연산자의 경우, 전위 연산자와는 다르게 추가적인 메모리가 필요하다.
후위 연산자가 들어가 있는 연산을 진행한 후에, 값을 변화시킨다.
변화한 값을 다른 연산을 진행한 후에! 가져와야하기 때문에 추가적인 메모리가 필요하다.
num++ = 30을 실행하면 '=': 왼쪽 피연산자는 l-value이어야 합니다.라는 오류가 발생한다.
이에 대해서 좀 더 풀어 써보자면, num은 메모리 주소를 가지고 있는 변수(객체)이기 때문에 l-value가 맞다.
하지만 num++ 표현식(expression)을 실행하면, num 객체에 1을 더한 값을 임의의 메모리에 저장해놓는다.
그리고 num에 들어있던 값(10)을 반환한다.
즉, 후위 연산자는 상수 값(const)를 반환한다! (반환형이 const 이다.)
num++ = 30은 10 = 10이라는 코드와 같다.
이는 좌항 우항 모두 r-value이므로, operator =의 피연산자가 l-value가 아니라는 오류가 뜰 수 밖에 없다.