본문 바로가기
C++

[c++] Reference

by 박새영 2021. 9. 21.

 

 

c로 프로그램을 작성하다가 c++로 넘어왔는데, c++에서는 c에서 쓰던 pointer 사용보다 reference의 사용을 권장하는 경우가 많았습니다.

 

Reference ?

reference 변수

#include <iostream>

int	main( void )
{
	std::string	a = "HI THIS IS BRAIN";
	std::string&	stringREF = a; // Reference 변수

	std::cout << &a << "\n";
	std::cout << &stringREF << "\n";
    
	std::cout << a << "\n";
	std::cout << stringREF << "\n";

	return (0);
}

 

 

a 변수와 stringREF 변수의 주소를 출력해보면 똑같은 주소가 출력됩니다.

 

-> 레퍼런스 변수는 개체의 다른 이름이다. 

 

 

 

파라미터 Reference

void swap(int& i, int& j)
{
  int tmp = i;
  
  i = j;
  j = tmp;
}

int main()
{
  int x, y;
  // ...
  swap(x,y);
  // ...
}

출처 (https://isocpp.org/wiki/faq/references#overview-refs)

 

 

 

c++에서는 기본적으로 함수 호출 시, 파라미터로 전달 된 변수는 값이 복사되어 사용됩니다. -> call by value

 

그래서 함수 내에서 파라미터 변수를 수정해도 원래 변수는 수정되지 않습니다. 그리고 함수 호출이 종료되면 파라미터와 지역변수 메모리가 해제되어 사용할 수 없습니다.

 

하지만 예시의 레퍼런스는 함수 호출에 사용된 실제 파라미터에 액세스하는 데 사용됩니다.

 

실제 파라미터의 값이 복사되지 않고 액세스 해 사용하기 때문에 길이가 긴 배열이나, 무거운 class 개체를 파라미터로 전달할때 그만큼의 메모리를 할당해 사용하지 않고 실제 파라미터에 액세스해 값을 사용할 수있습니다.

 

swap의 결과는 정상적으로 x와 y의 값이 서로 바뀌게 됩니다.

 

 

왜 Reference를 써야할까?

reference와 pointer는 비슷해보입니다. 하지만 pointer가 아니라 reference를 써야하는 이유가 있습니다.

 

 

reference는 안전합니다.

 

reference는 생성 시 바로 초기화 되어야 합니다. null로 초기화 할 수 없고, 한번 초기화되면 다른 개체를 참조하도록 수정할 수 없습니다.

 

reference 변수의 이런 제약이 reference 변수를 안전하게 사용할 수 있게 합니다.

 

하지만 pointer 변수는 null로 초기화 할 수 있고, 수정할 수 있습니다.

 

그래서 pointer 변수를 사용할때는 null 체크를 해야하고, 수정되어 내가 예상하는 값이 아니게 되었는지도 체크해야합니다.

 

 

reference는 코드 상에서 이해하기 쉽고, 사용하기에도 쉽습니다.

 

refernece 변수는 선언 시에만 & 연산자를 사용하고, 이후 일반 변수처럼 사용할 수 있습니다.

 

포인터는 값에 액세스하기 위해서는 역 참조 연산자 *가 필요하고, 객체 멤버에 액세스 하기 위해서는 화살표 연산자 -> 가 필요합니다.

 

 

 

레퍼런스 변수는 메모리 할당이 되지 않지 않는다?

 

 컴파일러가 제공하는 부분이라 컴파일러마다 상황에 따라 효율성을 고려해 구현이 달라질 수 있습니다.

 

많은 경우에 레퍼런스 변수가 포인터 변수처럼 구현이 됩니다. 그래서 레퍼런스가 포인터에 비해 메모리 효율에서 더 낫다고 말할수 없습니다.

 

하지만 둘은 구현은 비슷하나 다르게 사용되는 개념입니다.

 

레퍼런스 변수는 개체의 다른 이름입니다. 레퍼런스 개체와 별도로 레퍼런스 변수 자체에는 작업할 수 있는 구문이 없습니다.

 

포인터는 개체의 주소를 담는 변수입니다. 이중, 삼중 포인터로 만들 수도 있습니다.

 

어쩔수 없는 경우를 제외하고 포인터보다 레퍼런스 사용이 권장됩니다.

 

 

 

 

 

 

 

참고

https://stackoverflow.com/questions/3954764/how-are-references-implemented-internally

 

https://isocpp.org/wiki/faq/references#overview-refs