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

WestCoast·2022년 3월 5일
0

C, C++

목록 보기
7/12

1. 잘못된 예시


#include<iostream>
using namespace std;

// 항목 21의 '잘못된' 예시에 대한 코드입니다.

class Rational
{
public:
	Rational(int numerator = 0, int denominator = 1)
		: n(numerator), d(denominator)
	{
		cout << "Rational(int numerator, int denominator)" << endl;
	}

	Rational(const Rational& rational)
		: n(rational.n), d(rational.d)
	{
		cout << "Rational(const Rational& rational)" << endl;
	}

	~Rational()
	{
		cout << "~Rational()" << endl;
	}

public:
	int n = 0, d = 0;
private:
	// <잘못된 operator* 의 선언 형식>
	friend const Rational& operator*(const Rational& lhs, const Rational& rhs);
};

// <잘못된 operator* 의 선언 형식>
// - Rational& 즉 '참조값'을 반환하고 있다!
// -- result는 '지역 객체'이다. 함수와 생명을 같이한다.
// - 이 방법을 이용해도 r3에 원하는 값이 넣어지는 것을 확인했음
// -- 하지만 여전히 result의 '소멸자' 호출 후에 r3의 '복사 생성자'를 호출하므로 위험한 발상
const Rational& operator*(const Rational& lhs, const Rational& rhs)
{
	cout << "Rational& operator*" << endl;

	Rational result(lhs.n * rhs.n, lhs.d * rhs.d);
	return result;
}

int main()
{
	Rational r1(1, 2);
	Rational r2(3, 4);
	cout << "---------------operator 함수 호출-------------------" << endl;
	Rational r3 = r1 * r2;
	cout << "---------------operator 함수 종료-------------------" << endl;
	cout << "r3.n = " << r3.n << endl;
	cout << "r3.d = " << r3.d << endl;

	return 0;
}

출력예시

Rational(int numerator, int denominator)
Rational(int numerator, int denominator)
---------------operator 함수 호출-------------------
Rational& operator*
Rational(int numerator, int denominator)
~Rational()
Rational(const Rational& rational)
---------------operator 함수 종료-------------------
r3.n = 3
r3.d = 8
~Rational()
~Rational()
~Rational()

2. 올바른 예시


#include<iostream>
using namespace std;

// 항목 21의 '올바른' 예시에 대한 코드입니다.

class Rational
{
public:
	Rational(int numerator = 0, int denominator = 1)
		: n(numerator), d(denominator)
	{
		cout << "Rational(int numerator, int denominator)" << endl;
	}

	Rational(const Rational& rational)
		: n(rational.n), d(rational.d)
	{
		cout << "Rational(const Rational& rational)" << endl;
	}

	~Rational()
	{
		cout << "~Rational()" << endl;
	}

public:
	int n = 0, d = 0;
private:
	// <올바른 operator* 의 선언 형식>
	friend const Rational operator*(const Rational& lhs, const Rational& rhs);
};

// <올바른 operator* 의 선언 형식>
// - Rational 객체를 반환하자! (근데 이제 RVO를 곁들여서) 
// --> RVO(Return Value Optimization)
// -- RVO를 이용하면 오직 Rational의 '생성자'만을 호출한다
// -- 조금 더 최적화를 원한다면 inline 함수로 선언할 수 있겠다.
// - 임시객체 생성 후 반환한다면?
// -- 가능하지만 효율성 하락(생성자, 복사생성자, 소멸자 순으로 호출된다)
const Rational operator*(const Rational& lhs, const Rational& rhs)
{
	cout << "Rational operator*" << endl;
	return Rational(lhs.n * rhs.n, lhs.d * rhs.d);
}

int main()
{
	Rational r1(1, 2);
	Rational r2(3, 4);
	cout << "---------------operator 함수 호출-------------------" << endl;
	Rational r3 = r1 * r2;
	cout << "---------------operator 함수 종료-------------------" << endl;
	cout << "r3.n = " << r3.n << endl;
	cout << "r3.d = " << r3.d << endl;

	return 0;
}

출력예시

Rational(int numerator, int denominator)
Rational(int numerator, int denominator)
---------------operator 함수 호출-------------------
Rational operator*
Rational(int numerator, int denominator)
---------------operator 함수 종료-------------------
r3.n = 3
r3.d = 8
~Rational()
~Rational()
~Rational()
profile
게임... 만들지 않겠는가..

0개의 댓글