C++ - 레퍼런스
int x = 1;
int& xRef = x;
cout << x << endl; // 1
cout << xRef << endl; // 1
레퍼런스는 기존 변수에 새로운 이름을 하나 더 붙여주는 것과 같은 효과를 가진다. 위와 같이 변수 타입 뒤에 &를 붙여서 레퍼런스를 만들 수 있다. 일반 변수와 똑같은 방법으로 동작하지만 내부적으로는 원본 변수에 대한 포인터로 취급한다.
x = 2 ;
cout << x << endl; // 2
cout << xRef << endl; // 2
xRef = 3;
cout << x << endl; // 3
cout << xRef << endl; // 3
둘 중 하나만 변해도 그 결과가 두 변수 모두에 적용된다.
레퍼런스의 유용한 사용방식으로 함수의 매개변수를 레퍼런스 형식으로 전달하는 방법이 있다. 이 방법에는 두 가지의 장점이 있다.
- 함수 내부에서 매개변수의 값을 변경 시 외부에도 적용시킬 수 있다.
- 메모리 공간을 절약할 수 있다.
함수에 배열이나 포인터가 아닌 일반적인 변수는 값 전달 방식(pass by value)으로 처리된다. 이는 함수에 매개변수가 전달될 때 원래 변수가 전달되는 것이 아닌 복제본을 만들고 그 복제본에 원래 변숫값을 넣어서 전달하는 방식이다. 따라서 함수 내에서 매개변수 값을 변경해도 원래 변수에 적용되지 않는다.
void myFunc(int a)
{
a = 5;
}
int main()
{
int x = 1;
myFunc(x);
cout << x << endl; // 1
}
따라서 원레 함수 내에서 원래 변수를 변경하려면 포인터 형식으로 매개변수를 전달해서 바꾸어야 했다. 하지만 이는 포인터 연산이 많아져서 코드가 복잡해지고 에러 발생 확률이 높아진다. 따라서 이를 해결하기 위해 C++에서 제공하는 것이 레퍼런스 전달 방식(pass by reference)이다.
void myFunc(int& a)
{
a = 5;
}
int main()
{
int x = 1;
myFunc(x);
cout << x << endl; // 5
}
레퍼런스 형태의 매개변수로 함수를 정의해 두면 값을 전달할 때 그 변수에 대한 레퍼런스가 만들어진다. 이때 주의해야 할 점은 이러한 형태의 함수를 사용할 때 전달값으로 리터럴이 지정되면 컴파일 에러가 발생할 수 있다. 이러한 리터럴을 처리하기 위해서는 const 레퍼런스나 rvalue 레퍼런스가 사용돼야 한다.
레퍼런스 전달 방식의 두번째 장점은 메모리의 절약이다. 큰 구조체나 클래스를 함수에 전달해야 할 때 값 전달 방식으로 본제본을 만 들 경 우 부담스러울 수 있다. 이러한 경우 레퍼런스 형식으로 전달하면 내부적으로 주솟값이 전달되므로 메모리를 절약할 수 있다. 그러나 이때 원본이 바뀌면 안 되나 큰 구조체나 클래스를 전달해야 할 경우 const 레퍼런스를 사용할 수 있다.
void printStudent(const Student& myStu)
{
cout << myStu.ID << endl;
cout << myStu.GPA << endl;
}
const 레퍼런스를 사용할 시 원본 변수를 보존할 수 있고 또 변수가 복제되지 않기 때문에 좋은 성능을 유지할 수 있다. 따라서 함수에 객체를 전달할 때 전달할 객체를 함수 안에서 수정하려면 non-const 레퍼런스를 아니면 const 레퍼런스를 사용하는 것이 바람직하다.