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