Item20_'값에 의한 전달'보다는 '상수객체 참조자에 의한 전달' 방식을 택하는 편이 대개 낫다
챕터 핵심 내용
- 지역 스택 객체에 대한 포인터나 참조자를 반환하는 일, 혹은 힙에 할당된 객체에 대한 참조자를 반환하는 일, 또는 지역 정적 객체에 대한 포인터나 참조자를 반환하는 일은 그런 객체가 두 개 이상 필요해질 가능성이 있다면 절대로 하지 마라.
- 지역 스택 객체에 대한 포인터나 참조자를 반환하는 일, 혹은 힙에 할당된 객체에 대한 참조자를 반환하는 일, 또는 지역 정적 객체에 대한 포인터나 참조자를 반환하는 일은 그런 객체가 두 개 이상 필요해질 가능성이 있다면 절대로 하지 마라.
- 지역 객체에 대한 참조자(혹은 포인터)를 반환하는 함수는 어떤 함수든지 프로그램의 핵폭탄이 된다.
- 힙에 할당된 객체는 누군가가 메모리 해제를 해주어야만 한다.
- 지역 정적 객체를 사용하면 스레드 안전성 문제가 있다.
- 새로운 객체를 반환해야 하는 함수를 작성할 때엔 새로운 객체를 반환하게 하자.(pass by value)
- 여기에 들어가는 비용은 올바른 동작에 지불되는 작은 비용이다.
후기(postscript)
컴파일러는 이러한 객체들에 대해, 반환 값 최적화(RVO, Return Value Optimization)를 한다. 반환 값 최적화는 이동 의미론이 적용된 것이기 때문에 비용이 많이 들지 않는다. 이는 임시 객체뿐만 아니라, 이름 있는 객체에도(NRVO, Named RVO) 적용된다.
class Rational {...}; const Rational operator*(const Rational& lhs, const Rational& rhs) { return Rational(lhs.numer * rhs.numer, lhs.denom * rhs.denom); // RVO } const Rational operator*(const Rational& lhs, const Rational& rhs) { Ration retVal(lhs.numer * rhs.numer, lhs.denom * rhs.denom); return retVal // NRVO }