KoreanFoodie's Study

Effective C++ | 항목 21 : 함수에서 객체를 반환해야 할 경우에 참조자를 반환하려고 들지 말자 본문

Tutorials/C++ : Advanced

Effective C++ | 항목 21 : 함수에서 객체를 반환해야 할 경우에 참조자를 반환하려고 들지 말자

GoldGiver 2022. 10. 25. 16:13

C++ 프로그래머의 필독서이자 바이블인, 스콧 마이어스의 Modern Effective C++ 를 읽고 기억할 내용을 요약하고 있습니다. 꼭 읽어보시길 추천드립니다!

항목 21 : 함수에서 객체를 반환해야 할 경우에 참조자를 반환하려고 들지 말자

핵심 :

1. 지역 스택 객체에 대한 포인터나 참조자를 반환하는 일, 혹은 힙에 할당된 객체에 대한 참조자를 반환하는 일, 또는 지역 정적 객체에 대한 포인터나 참조자를 반환하는 일은 그런 객체가 두 개 이상 필요해질 가능성이 있다면 절대로 하지 말자(항목 4를 보면 단일 스레드 환경에서의 적절한 코드 예제를 찾을 수 있다)

 

유리수를 표현하는 클래스의 곱셈 operator 를 다음과 같이 정의하면, 각기 다른 문제가 발생한다!

// 1. result 객체를 생성 (스택 영역)
const Rational& operator*(const Rational& lhs, const Rational& rhs)
{
  Rational result(lhs.n * rhs.n, lhs.d * rhs.d);
  // Dangling Pointer
  // 지역변수인 result 는 소멸하는데, 이에 대한 참조자를 리턴!
  return result;
}

// 2. result 객체를 생성 (힙 역역)
const Rational& operator*(const Rational& lhs, const Rational& rhs)
{
  Rational *result = new Rational(lhs.n * rhs.n, lhs.d * rhs.d);
  // Memory Leak
  // new 로 생성한 result 는 어디에서 delete ...?
  return *result;
}

// 3. 대환장 코드
const Rational& operator*(const Rational& lhs, const Rational& rhs)
{
  static Rational result;
  result = Rational(lhs.n * rhs.n, lhs.d * rhs.d);
  return result;
}

// 3번을 사용하면...
Rational a, b, c, d;
...
if ((a*b) == (c*d))
{
  // 위 if 식은 항상 true
  // operator 의 결과값은 같은 static 객체인 result 일 것이기 때문!
}

올바른 코드는 다음과 같을 것이다.

const Rational operator*(const Rational& lhs, const Rational& rhs)
{
  return Rational(lhs.n * rhs.n, lhs.d * rhs.d);
}

위의 연산에 필요한 비용은 작은 비용이다. 나머지는 컴파일러의 최적화 능력을 믿어보도록 하자.

Comments