일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
Tags
- 게임
- 언리얼
- UE4
- 영화 리뷰
- 암시적 변환
- 예외
- 비교 함수 객체
- effective stl
- 다형성
- implicit conversion
- 참조자
- lua
- virtual function
- Vector
- 루아
- Effective c++
- operator new
- reference
- 영화
- more effective c++
- exception
- 메타테이블
- 상속
- resource management class
- 반복자
- 오블완
- 스마트 포인터
- 티스토리챌린지
- c++
- Smart Pointer
Archives
- Today
- Total
스토리텔링 개발자
[Effective C++] 21. 참조자를 리턴하면 안되는 상황 본문
728x90
항목 21. 함수에서 객체를 반환해야 할 경우에 참조자를 반환하려고 들지 말자
모든 코드에 '참조에 의한 전달'을 반영하려들면 안 되는 이유
-
class Rational { public: Rational(int numerator = 0, int denominator = 1); ... private: int n, d; friend const Rational operator* (const Rational& lhs, const Rational& rhs); }; ... Rational a(1, 2); // a = 1/2 Rational b(3, 5); // b = 3/5 Rational c = a * b; // c는 3/10이 되어야 한다.
- 참조자는 존재하는 객체에 붙는 이름일 뿐이다.
- 즉, 참조자를 리턴하려면 이미 존재하는 Rational 객체의 참조자여야 한다.
- operator*가 참조자를 리턴한다면
- 위 예제, c = a * b 에서 a * b의 결과로 도출되는 Rational은 언제 생성된 것을 리턴할 것인가?
참조자 반환을 위한 여러 가지 시도
- 스택에 새로운 객체를 만드는 방법
-
const Rational& operator* (const Rational& lhs, const Rational& rhs) { Rational result(lhs.n * rhs.n, lhs.d * rhs.d); // 스택 생성 return result; }
- 스택 객체는 참조자 반환 시점에는 소멸하게 되는데, 그렇다면 이미 소멸된 객체의 참조자가 반환된다는 뜻이다.
- 생성자가 불리는 걸 피하고자 참조자 반환을 했을텐데, 결과적으론 객체를 생성하는 꼴이 된다.
-
- 힙에 새로운 객체를 만드는 방법
-
const Rational& operator* (const Rational& lhs, const Rational& rhs) { Rational* result = new Rational(lhs.n * rhs.n, lhs.d * rhs.d); return *result; };
- 여전히 생성자를 한번 호출한다.
- 메모리 누수의 문제가 있다. 이 힙 생성에 대한 뒷처리(delete를 짝지어주기)가 힘들어지기 때문이다.
-
Rational w, x, y, z; w = x * y * z; // delete를 어떻게 짝지어줄 것인가?
-
-
- 함수 내에 정적 객체를 정의하는 방법
-
const Rational& operator* (const Rational& lhs, const Rational& rhs) { static Rational result; // 반환에 사용할 정적 객체 result = ...; return result; }
- 스레드 안정성 문제가 있다.
- 해당 함수의 리턴값들을 비교하는 코드에서 늘 true를 반환하게 된다.
-
Rational a, b, c, d; ... if((a * b) == (c * d)) { ... } // 이 경우 어떻게 될까?
-
- 그렇다면 정적 객체를 배열로 만들면?!
- 해당 배열의 크기는 어떻게 정의할 것인가.
- 너무 큰 크기를 할당해두면 되려 수행 성능이 떨어진다. 이는 기존의 의미를 퇴색시키는 일.
-
새로운 객체를 반환하는 함수의 정도
- 새로운 객체를 반환하게 만들자.
const Rational operator*(const Rational &lhs, const Rational& rhs)
{
return Rational(lhs.n * rhs.n, lhs.d * rhs.d);
}
- 생성 / 소멸 비용이 들어가지만 올바른 동작에 지불되는 작은 비용이다.
- 반환값 최적화(return value optimization)(RVO)의 여지
- C++ 컴파일러는 기존 코드의 수행 성능을 높이는 최적화를 적용할 수 있다.
- 그 결과로 컴파일 후 해당 반환값에 대한 생성 / 소멸 동작이 안전하게 제거될 여지가 있다.
728x90
'개발 > Effective C++' 카테고리의 다른 글
[Effective C++] 23. 비멤버 비프렌드 함수 (0) | 2024.06.18 |
---|---|
[Effective C++] 22. 데이터 멤버 확실히 숨기기 (0) | 2024.06.17 |
[Effective C++] 20. const & 전달하기 (0) | 2024.06.13 |
[Effective C++] 19. 클래스 설계 (0) | 2024.06.12 |
[Effective C++] 18. 인터페이스 설계 (1) | 2024.06.11 |
Comments