스토리텔링 개발자

[More Effective C++] 7. operator&& / operator|| / operator, 본문

개발/More Effective C++

[More Effective C++] 7. operator&& / operator|| / operator,

김디트 2024. 8. 7. 11:36
728x90

항목 7 : &&, ||, 혹은 , 연산자는 오버로딩 대상이 절대로 아니다

 

 

 

단축 평가(short-circuit)
  • C와 마찬가지로 C++ 역시 복합적인 불린 표현식을 평가할 때 단축 평가 처리를 할 수 있다.
  • 즉, 표현식의 일부가 참, 거짓임이 판명되면, 그 이후의 표현식은 무시하고 평가를 중단한다.
// 1.
char* p;
// 이 경우, p != 0 이 거짓으로 판명되면 strlen이 호출될 걱정을 할 필요가 없다.
// 즉, null 포인터에 대한 strlen 호출이 되지 않음을 가정하고 작성한 코드이다.
// null 포인터에 대한 strlen 호출은 미정의 사항이기 때문이다.
if((p != 0) && (strlen(p) > 10))
{ ... }

// 2.
int rangeCheck(int index)
{
    // index가 lowerBound보다 작으면 upperBound와 비교될 일이 없다.
    if((index < lowerBound) || (index > upperBound)) ...
}

 

 

 

operator&&와 operator|| 함수 오버로딩
  • 이 두 연산자의 기능을 바꾼다는 것은 아래와 같은 의미이다.
    • 본래의 단축평가 의미구조(short-circuit semantics)를 함수호출 의미구조(function call semantics)로 대체한다.
if(expression1 && expression2) ...
// &&, || 연산자를 재정의하면
// 위의 if 문은 컴파일러에게 아래처럼 보인다는 뜻이다.

// operator&&가 멤버 함수일 경우
if(expression1.operator&&(expression2)) ...

// operator&&가 전역 함수일 경우
if(operator&&(expression1, expression2)) ...

 

 

 

 

함수 호출이 단축평가와 다른 점
  1. 함수 호출이 이루어질 때는 모든 매개변수를 평가한다.
    • 즉 단축평가가 이루어지지 않는다.
  2. C++ 명세서에는 함수 호출에 사용되는 매개변수의 평가 순서가 명시되어 있지 않다.
    • 즉, 순서대로 평가된다는 보장이 없다.
    • 허나 단축평가는 항상 왼쪽에서 오른쪽으로 평가한다.

 

 

 

쉼표 연산자
  • 표현식을 꾸미는 용도로 사용한다.
void reverse(char s[])
{
    for(int i = 0, j = strlen(s) - 1 ; i < j; ++i, --j) // 쉼표 연산자 사용
    {
        int c = s[i];
        s[i] = s[j];
        s[j] = c;
    }
}
  • 쉼표 연산자의 규칙
    1. 왼쪽에서 오른쪽으로 평가한다.
    2. 쉼표가 쓰인 전체 표현식의 결과는 오른쪽에 있는 표현식의 값이다.
      • 즉, (++i, --j)의 경우 결과값은 --j의 값이다.
  • 쉼표 연산자 오버로딩의 문제점
    • 쉼표 연산자가 전역 함수로 만들어진 경우
      • 왼쪽 표현식이 오른쪽 표현식보다 먼저 평가된다고 보장할 수 없다.
    • 쉼표 연산자가 멤버 함수로 만들어진 경우
      • 왼쪽 피연산자가 먼저 평가된다는 확신을 할 수 없다.

 

 

오버로딩 할 수 없는 연산자의 종류
. .* :: ?:
new delete sizeof typeid
static_cast dynamic_cast const_cast reinterpret_cast

 

 

 

오버로딩 가능한 연산자의 종류
operator new operator delete
operator new[] operator delete[]
+ - * / % ^ & | ~
! = < > += -= *= /= %=
^= &= |= << >> >>= <<= == !=
<= >= && || ++ -- , ->* ->
() []              

 

 

 

결론
  • 단순히 오버로딩 가능하다고 오버로딩을 하진 말 것.
  • && || , 연산자는 아무리 용을 써도 원래 연산자처럼 동작하도록 만들 수가 없기 때문이다.

 

 

 

참조
 

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

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

delightlane.tistory.com

 

728x90
Comments