본문 바로가기
IT/C++(CPP)

CPP 초급 강좌 21. C++ reference return, rvalue reference &&

by 신림83 2020. 10. 31.
반응형

CPP 초급 강좌 21. C++ reference return, rvalue reference &&

이전 글에서 call by value, call by reference 에 대하여 (함수인자 사용을 통해) 살펴본 적이 있는데요, 

관련링크

 

CPP 초급 강좌 19. C++ 레퍼런스 reference

CPP 초급 강좌 19. C++ 레퍼런스 reference 레퍼런스에 대해 알아보겠습니다.  C++에서 레퍼런스란 무엇인가를 알기 위해 기존의 변수 라는 표현이 뭔가를 정리해 볼까요? 변수  메모리의 특정 위치를

sillim83.tistory.com

이번에는 reference return 에 대해 보겠습니다.

return by value

아래 코드를 볼까요.

class Point
{
public:
	float x = 0.0f;
	float y = 0.0f;
};

Point p;

Point f1()
{
	return p;
}

int main()
{
	f1().x = 100;
}

가능할까요? 답은 불가합니다.

에러

return by reference

 좀 더 자세히 안 되는 이유를 설명하면, f1()의 리턴인 Point는 return by value 입니다. 리턴시 복사가 일어나 임시객체가 반환되는 상태입니다. 값을 수정할 수 없습니다.

 위의 코드가 전역의 생성된 Point p;를 반환하려는 의도였다면, return by reference 로 접근해야 합니다.

Point& f1()
{
	return p;
}

int main()
{
	f1().x = 100;

	cout << p.x << endl;
}

이와 같은 코드는 가능합니다.

 

출력결과

정리하면

 return by value 복사된 값을 넘겨줍니다. 리턴 값을 즉시 사용할 수 없습니다.

 return by refererce 복사본인 아닌 실제값을 다른 이름, 그냥 실제 값이라고 생각하시면 편합니다. 

용도에 맞게 사용하시면 됩니다.

 

primitive type

return value 값 적용은 되지 않는다.

int n;
int& f1()
{
	return n;
}

int main()
{
	f1() = 100;
}

문제없는 코드

 

시스템이 제공해주는 primivie type(int,float,double...)등 또한 똑같이 작동됩니다.

 

지역변수 주의

int& f1()
{
	int n1;
	return n1;
}

이런 코드는 어떨까요? 지역변수를 선언하고 그 변수를 리턴합니다. return by reference 입니다.

 

컴파일러는 일단, warning C4172: 지역 변수 또는 임시: n1의 주소를 반환하고 있습니다. 을 주긴 하지만 프로그램 자체는 빌드도 되고 돌아갈 수 있습니다.

 

하지만 위의 코드는 정말 위험한 코드입니다.

 

 n1은 기본적으로 지역변수입니다. 해당 함수에서 생명력을 다하게 되는데 그 값을 주소를 반환시키는 행위입니다. 컴파일러에 따라 해당 영역을 메모리를 바로 회수하거나 좀 더 그 시점이 뒤 일수 있는데요, 차라리 바로 회수되고 프로그램이 터지면 다행입니다. 이는 에러를 인지하고 바로 수정할 수 있으니까요.

 

 가끔 회수 시점이 틀릴 수가 있습니다. 그리고 프로그램 사용자가 느끼기에 랜덤하다고 생각할 확률이 큽니다. 프로그램이 구동하나 어느 시점에서 죽을지 알 수가 없는 위험도가 있는 코드입니다. 큰 프로그램이라면 이런 오류는 정말로 대응하기 어렵습니다.

 

주의가 필요한 코드입니다.

 

rvalue reference

다음 코드를 보아요.

int n1 = 0, n2 = 0;

n1 = 0;		//a
0 = n1;		//b
n2 = n1;	//c

a는 가능한 코드입니다.

b는 불가능한 코드입니다. 0은 우변에는 올 수 있지만 좌변에는 위치할 수 없습니다.

c는 가능한 코드입니다.

 

0과 같이 우변에만 올 수 있는 값들을 cpp에서는 rvalue 라고 합니다.

반대로 n1과 같이 우변에도, 좌변에도 올수 있는 경우 lvalue 라고 합니다.

 

레퍼런스에서는 어떨까요? 다음 코드를 봅시다.

int& r1 = n1;	//d
int& r2 = 10;	//e

d는 이미 많이 본 코드이며 가능한 코드입니다. e는 불가능한 코드입니다. 레퍼런스는 rvalue를 담을수 없습니다.

 

하지만 다음과 같은 코드는 또 가능합니다.

const int& r3 = n1;	//f
const int& r4 = 10;	//g

f, g 모두 가능한 코드입니다. const & 일 경우는 우변이 lvalue, rvalue 모두 담을수 있습니다.

 

c++11 부터 rvalue 만 담을 수 있는 reference 형식이 나왔습니다.

int&& r5 = n1;	//h
int&& r6 = 10;	//i

h는 불가합니다. i 코드만 가능합니다. && 는 rvalue reference는 rvalue만 담기 위한 문법입니다.

형식&& 요것이 등장하면서 기존에 형식& 만 존재할 때와 명칭이 조금 달라졌습니다.

 

이전에는(c++11) 레퍼런스라고 하면 

형식&

 

현재(c++11) 이후는 아래 둘다 래퍼른스입니다.

형식& 더 정확한 명칭은 lvalue reference

형식&& 더 정확한 명칭은 rvalue reference

 

뭐여? 이런건 왜 있는 거여 라고 하여 사용 용도를 보여드리고 싶은데, 요게 사용되는 부분이, 

move semantics, perfect forwarding 등 난이도가 있는 주제라서, 지금은 그냥 아 이런 기능이 있구나 정도로 보고 넘어가시는 게 좋을 거 같습니다.

 

공부합시다.

 

반응형

댓글