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

업데이트:     Updated:

카테고리:

태그:

이 글은 아래의 책을 자세히 정리한 후, 정리한 글을 GPT에게 요약을 요청하여 작성되었습니다.
이펙티브 C++ 제3판, 스콧 마이어스 저자, 곽용재 번역

📦 4. 설계 및 선언Permalink

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

‘값에 의한 전달’이 성능 상 좋지 않다는 이유로, ‘참조에 의한 전달’을 고집하는 것이 좋지 않은 경우가 있다.

아래 코드를 살펴보자.

class Rational {
public:
	Rational(int numerator = 0, int denominator = 1);
	...

private:
	int n, d; // 분자, 분모

	friend const Rational operator*(const Rational& lhs, const Rational& rhs);
};

이 클래스는 유리수를 표현하고, 곱셈 연산을 정의한다.
곱셈 연산자는 ‘값에 의한 반환’을 하고 있는데, 누군가는 이 비용이 아깝다고 생각할 수 있다.

그래서 아래와 같은 방식으로 ‘참조 반환’ 을 시도할 수도 있다.


➡️ ‘참조에 의한 전달’ 구현 시도Permalink

1. 스택에 객체 생성 후 참조 반환Permalink

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

❌ 문제점

  • result는 지역 객체라 함수 종료 시 소멸된다.
  • 즉, 소멸된 객체를 참조하고 있는 꼴이 된다.

2. 힙에 객체 생성 후 참조 반환Permalink

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

❌ 문제점

  • 힙 객체는 수동으로 소멸시켜야 한다.
  • 하지만 w = x * y * z 같은 식에서는 중간에 생성된 객체를 어디서 어떻게 delete 할지 알 수 없다.

    → 결국 메모리 누수로 이어진다.


3. 정적 객체 반환Permalink

const Rational& operator*(const Rational& lhs, const Rational& rhs) {
	static Rational result;
	result = ... // 연산 수행
	return *result;
}

❌ 문제점

  • 정적 객체는 하나만 존재한다.
  • a*b == c*d 같은 비교 연산을 하면, 모든 결과가 같은 객체를 가리키기 때문에 항상 같다고 판단할 수도 있다.
  • 게다가 다중 스레드 상황에서는 데이터 레이스가 발생한다.

3.1. 정적 배열 사용Permalink

❌ 문제점

  • 배열의 크기를 미리 정해야 한다.
  • 크기가 작으면 공간 부족, 크면 성능 저하
  • 호출될 때마다 n개의 객체가 생성되고 파괴됨 → 오히려 낭비

✅ 해결법Permalink

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

→ 그냥 ‘값에 의한 반환’을 사용하면 된다.

현대 컴파일러는 RVO(Return Value Optimization)move semantics 덕분에 이 방식이 오히려 더 깔끔하고 효율적이다.


🧐 정리Permalink

  • 아래의 방식은 사용하지 말자:
    • 스택 객체의 참조자나 포인터를 반환
    • 힙 객체의 참조자 반환 (소멸 시점을 제어할 수 없음)
    • 정적 객체 또는 배열을 활용한 참조자 반환 (동시성, 재사용 문제)

→ 결국에는 모두 의도치 않은 부작용이나 버그로 이어진다.

그러니 객체 반환이 필요하면, 값에 의한 반환을 주저하지 말자.

Cpp 카테고리 내 다른 글 보러가기

댓글남기기