논리 연산자 오버로딩

Jaemyeong Lee·2024년 8월 17일
0

FastCampusC++

목록 보기
62/78

논리 연산자 오버로딩의 위험성과 평가 순서 문제

C++에서는 논리 연산자 &&||를 오버로딩할 수 있습니다. 하지만, 이러한 오버로딩은 매우 신중하게 사용해야 합니다. 이 코드와 주석을 통해 논리 연산자 오버로딩의 문제점과 평가 순서(Squence Point)가 깨질 수 있는 위험성에 대해 자세히 분석해보겠습니다.


1. 논리 연산자 오버로딩

String 클래스 정의

class String
{
private:
    char* _chars;

public:
    String(const char* chars) : _chars(new char[strlen(chars) + 1])
    {
        strcpy(_chars, chars);
    }

    bool operator!() const
    {
        return strlen(_chars) == 0;
    }

    bool operator&&(bool b) const
    {
        return strlen(_chars) > 0 && b;
    }

    bool operator||(bool b) const
    {
        return strlen(_chars) > 0 || b;
    }
};
  • operator! 오버로딩: 문자열이 빈 문자열("")인지 확인하는 연산자입니다. 문자열이 비어있다면 true를 반환하고, 그렇지 않으면 false를 반환합니다.

  • operator&& 오버로딩: 문자열이 비어있지 않으면 true로 평가되고, 전달된 bool 값과 논리 AND 연산을 수행합니다. 문자열이 비어있다면 false를 반환합니다.

  • operator|| 오버로딩: 문자열이 비어있지 않으면 true로 평가되고, 전달된 bool 값과 논리 OR 연산을 수행합니다. 문자열이 비어있다면 falsebool 값의 OR 연산을 수행합니다.

2. main 함수 분석

bool func()
{
    cout << "func" << endl;
    return true;
}

int main()
{
    String s("");
    if (!s)
    {
        cout << "s" << endl;
    }

    String s0("abc");
    if (s0 || func())
    {
        cout << "!!" << endl;
    }
}
  • func 함수: func 함수는 단순히 "func"를 출력하고 true를 반환합니다. 이 함수는 논리 연산자 오버로딩의 문제점을 보여주기 위해 사용됩니다.

  • if (!s): 이 부분은 잘 동작합니다. ! 연산자를 오버로딩했기 때문에, s가 빈 문자열인지 체크하는 코드입니다. 빈 문자열이라면 true가 되어 "s"가 출력됩니다.

  • if (s0 || func()): 이 부분에서 논리 연산자 오버로딩의 문제점이 드러납니다. s0가 비어 있지 않다면 true로 평가되며, C++에서 일반적으로 || 연산자는 Short-circuit evaluation을 수행합니다. 즉, s0true라면 func()는 호출되지 않아야 합니다.

    그러나, 오버로딩된 operator||Short-circuit evaluation을 보장하지 않습니다. 이 때문에 s0true임에도 불구하고 func()가 호출되어 "func"가 출력됩니다. 또한, 평가 순서도 보장되지 않기 때문에 s0func() 중 무엇이 먼저 평가될지는 정의되지 않습니다.


3. 논리 연산자 오버로딩의 위험성

Short-circuit Evaluation의 손실

  • Short-circuit evaluation은 논리 연산에서 중요한 개념으로, && 연산자에서는 왼쪽 피연산자가 false인 경우 오른쪽 피연산자를 평가하지 않고 false를 반환하며, || 연산자에서는 왼쪽 피연산자가 true인 경우 오른쪽 피연산자를 평가하지 않고 true를 반환하는 방식입니다.
  • 오버로딩된 논리 연산자는 이 평가를 보장하지 않기 때문에, 코드의 의도와 다르게 불필요한 함수 호출이 발생할 수 있으며, 이는 성능 저하를 초래하거나 부작용(side effect)을 일으킬 수 있습니다.

평가 순서(Squence Point) 문제

  • C++에서 연산자는 보통 특정한 평가 순서(Sequence Point)를 가지며, 이는 연산자 평가가 이루어지는 시점과 순서를 명확하게 정의합니다.
  • 논리 연산자(&&, ||)는 평가 순서를 보장하지만, 이를 오버로딩하게 되면 이 순서가 보장되지 않습니다. 즉, 어떤 피연산자가 먼저 평가될지 알 수 없게 되며, 이는 예측할 수 없는 버그를 유발할 수 있습니다.

4. 결론

논리 연산자 오버로딩은 C++에서 강력한 기능이지만, 예상치 못한 결과를 초래할 수 있기 때문에 매우 신중하게 사용해야 합니다. 특히 Short-circuit evaluation이 보장되지 않는다는 점과 평가 순서가 깨질 수 있다는 점에서 심각한 문제가 발생할 수 있습니다. 이러한 문제를 피하기 위해서는 논리 연산자의 오버로딩을 가급적 피하고, 표준적인 논리 연산자를 사용하는 것이 좋습니다.


블로그 포스트 요약

이번 포스트에서는 C++의 논리 연산자 오버로딩의 위험성과 그로 인해 발생할 수 있는 문제점들에 대해 다루었습니다. 주요 내용은 다음과 같습니다:

  1. Short-circuit Evaluation:

    • 논리 연산자 &&, ||는 기본적으로 Short-circuit evaluation을 수행합니다.
    • 오버로딩된 논리 연산자는 이 평가를 보장하지 않으며, 이는 예기치 않은 함수 호출과 성능 저하를 초래할 수 있습니다.
  2. 평가 순서 문제:

    • 논리 연산자는 평가 순서를 보장합니다.
    • 오버로딩된 논리 연산자는 이러한 순서를 깨뜨릴 수 있으며, 예측할 수 없는 결과를 초래할 수 있습니다.
  3. 논리 연산자 오버로딩의 주의점:

    • 논리 연산자를 오버로딩할 때는 이로 인해 발생할 수 있는 문제들을 인식하고 신중하게 사용해야 합니다.
    • 가급적 논리 연산자의 오버로딩을 피하고, 표준적인 연산자를 사용하는 것이 더 안전한 선택일 수 있습니다.

이 내용을 바탕으로 논리 연산자 오버로딩의 위험성과 문제점을 복습하고, C++ 프로그래밍에서의 사용법을 신중히 고려하는 습관을 길러보세요!

profile
李家네_공부방

0개의 댓글