C 언어의 포인터와 유사한 개념으로 어떠한 변수를 가리킬 때 사용하는 방법
레퍼런스를 선언할 때는 가리키고 싶은 변수 타입 뒤에 &를 붙이면 된다. (ex. int형 변수의 레퍼런스의 경우 int&)
레퍼런스는 변수에 별명을 추가하는 것으로 생각하면 된다. 아래 예시의 경우, a_ref는 변수 a의 별명이 되는 것이다.
#include <iostream>
using namespace std;
int main() {
int a = 5;
int& a_ref = a;
cout << a << endl;
cout << a_ref << endl;
return 0;
}
5
5
레퍼런스를 선언할 때 어떤 변수를 반드시 참조해야 된다.
int& a_ref;
(X)
int& a_ref = a;
(O)
상수에 대한 레퍼런스를 선언할 때는 자료형 앞에 const
를 붙여 이용하면 된다.
int& ref = 10;
(X)
const int& ref = 10;
(O)
레퍼런스의 배열은 불가능하지만 배열의 레퍼런스는 가능하다.
레퍼런스의 배열의 경우, 배열의 원소에 접근할 때 주소값으로 변환이 될 수 있어야 하는데, 그 의미는 해당 원소가 메모리 상에서 존재한다는 의미이기 때문에 메모리 상에서 공간을 차지하지 않을 수 있는 레퍼런스와 모순이 된다.
배열의 레퍼런스를 선언할 때는 아래와 같이 참조하는 배열의 크기와 알맞게 명시해야 한다.
int arr1[3] = {1, 2, 3};
int(&ref1)[3] = arr1;
int arr2[5] = {1, 2, 3, 4, 5};
int(&ref2)[5] = arr2;
int& func() {
int a = 1;
return a;
}
int main() {
int b = func();
b = 2;
return 0;
}
위의 경우에는 오류가 발생한다.
Why? int b = func();
의 부분에서 func()
안의 a
는 함수의 리턴과 동시에 사라지기 때문에 func()
이 반환하는 레퍼런스가 참조의 대상을 잃게 되어 Dangling Reference가 되기 때문이다.
int& func(int& a) {
a = 1;
return a;
}
int main() {
int b = 2;
int c = func(b);
return 0;
}
하지만 위의 경우, func()
안의 a
는 main
안의 b
를 참조하고 있기 때문에 func()
이 반환하는 레퍼런스는 프로그램 종료 전까지 b
를 계속 참조하고 c
는 현재 b
의 값을 복사한다.
int func() {
int a = 1;
return a;
}
int main() {
int& b = func();
return 0;
}
위의 경우에도 int& b = func();
에서 func()
의 a
가 리턴과 동시에 사라지기 때문에 b
는 Dangling Reference가 된다.
int func() {
int a = 1;
return a;
}
int main() {
const int& b = func();
return 0;
}
하지만 const
키워드를 통해 상수 레퍼런스로 받게 될 경우 함수의 리턴값이 레퍼런스가 사라질 때까지 계속 남아있다.
함수에서 값 리턴 (int f() ) | 함수에서 참조자 리턴 (int& f() ) | |
---|---|---|
값 타입으로 받음 (int a = f() ) | 값 복사됨 | 값 복사됨 (지역 변수의 레퍼런스를 리턴하지 않도록 주의) |
참조자 타입으로 받음 (int& a = f() ) | 컴파일 오류 | 가능 (지역 변수의 레퍼런스를 리턴하지 않도록 주의) |
상수 참조자 타입으로 받음 (const int& a = f() ) | 가능 | 가능 (지역 변수의 레퍼런스를 리턴하지 않도록 주의) |
출처: 모두의 코드