스토리텔링 개발자

[More Effective C++] 6. operator++ / operator-- 본문

개발/More Effective C++

[More Effective C++] 6. operator++ / operator--

김디트 2024. 8. 6. 11:25
728x90

항목 6 : 증가 및 감소 연산자의 전위 / 후위 형태를 반드시 구분하자

 

 

 

++, -- 연산자 오버로드 규칙의 필요성
  • 80년대 후반에는 전위, 후위 방식으로 호출하는 것을 구분할 방법이 없었다.
  • 그래서 해당 연산자의 전위 / 후위 형태를 오버로딩 할 수 있도록 스팩이 향상되었다.
  • 근데 오버로딩은 보통 매개변수의 타입에 따라 구분되는데?
    • 증감 연산자는 인자를 전혀 받지 않는다는 문제가 있다.
    • 그래서 아래의 규칙이 생겨났다.

 

 

 

증감 연산자의 오버로딩 규칙
  1. 후위 형태는 int 타입의 인자를 받는다.
    • 증감 연산자가 후위로 호출될 때 컴파일러는 해당 인자로 0을 넘겨준다.
  2. 전, 후위 형태는 서로 다른 타입을 반환한다.
    • 전위 형태
      • 참조자 타입을 리턴
    • 후위 형태
      • const 객체 타입을 리턴
class UPInt
{
public:
    UPInt& operator++(); // 전위 ++
    const UPInt operator++(int); // 후위 ++
    
    UPInt& operator--(); // 전위 --
    const UPInt operator--(int); // 후위 --
    
    UPInt& operator+=(int); UPInt와 int에 대한 +=
    ...
};

UPInt i;

++i; // i.operator++() 호출
i++; // i.operator++(0) 호출

--i; // i.operator--() 호출
i--; // i.operator--(0) 호출

 

 

 

전, 후위 연산자의 반환값이 다른 이유
  • 연산자의 용법이 다르기 때문이다.
    • 전위 형태
      • 증가시키고 값을 사용한다.(increment and fetch)
    • 후위 형태
      • 값을 사용하고 증가시킨다.(fetch and increment)
UPInt& UPInt::operator++() // 전위 형태
{
    *this += 1; // 증가시킨다.
    return *this; // 값을 가져온다.
}

const UPInt UPInt::operator++(int) // 후위 형태
{
    // 매개변수 int는 사용하지 않는다.
    // 그저 전, 후위를 구분하기 위한, 오버로드 구분용이기 때문이다.
    // 이름이 붙은 매개변수는 사용하지 않으면 경고가 나올 수 있으므로,
    // 이름을 생략해 버렸다.

    const UPInt oldValue = *this; // 값을 가져온다.
    ++(*this); // 증가시킨다.
    
    return oldValue; // 저장해둔 값을 반환한다.
}
  • 헌데 왜 후위 연산자의 리턴값은 const여야 할까?
    1. 기본 제공(built-in) 타입 증가 연산자의 동작과 일치시키기 위함이다.
      • 클래스를 설계할 때, "아리송하면 int의 동작원리대로 만들어라"
    2. 사용자가 직관적으로 이해하지 못할 동작을 원천 차단시켜야 한다.
UPInt UPInt::operator++(int); // const가 빠진 후위 연산자

UPInt i;

// 후위 증가 연산자를 두 번 적용한다.
i++++; // i.operator++(0).operator++(0); 과 같은 코드

////////////////////////
// 기본 제공 타입의 경우
int ri;
ri++++; // 컴파일 에러 발생!

////////////////////////
// 또한 const 빠진 후위 연산자를 그대로 사용하면
i++++; // i의 값은 한 번만 증가한다.
// 첫 번째 ++연산자의 반환값 : 값이 증가하기 전의 임시객체
// 두 번째 ++연산자는 값이 증가하기 전의 임시객체에 대해 값을 증가시키므로.
// 이는 i의 값이 두 번 증가하리라 예상하는 사용자의 직관과 다르다.

 

 

 

후위 연산자의 비효율성
  • 반환값으로 쓰기 위한 임시 객체가 필요하다.(항목 19 참조)
  • 심지어 해당 임시 객체는 지역 변수로서 생겼다가 없어지는 것이다.
  • 그러므로 전위 / 후위를 비교하면 전위 연산자가 효율적이다.

 

 

전, 후위 연산자의 동작이 동일하다는 보장
  • 전, 후위 연산자는 반환 타입을 제외하면 하는 일이 같다.
  • 그러므로 시간이 지나더라도 동작 방식을 보장하기 위해서는..
    • 후위 증감 연산자는 반드시 전위 증감 연산자를 사용해서 구현하도록 하자.

 

 

 

참조
 

[Effective C++] 18. 인터페이스 설계

항목 18. 인터페이스 설계는 제대로 쓰기엔 쉽게, 엉터리로 쓰기엔 어렵게 하자   제대로 쓰기엔 쉽고 엉터리로 쓰기엔 어려운 인터페이스 개발사용자가 저지를만한 실수의 종류를 머리에 넣

delightlane.tistory.com

 

728x90
Comments