11장 - 레퍼런스

1) 레퍼런스란?

변수에 대한 일종의 별칭(alias)이다. 변수의 주소를 가져오거나 변수에 대한 역참조 연산을 수행하는 특수 포인터라고 할 수도 있다. 기호는 &이다.

int x = 3                   
int& xRef = x; 

int& unRef1 = 5;           // 에러! 리터럴은 변경할 수 없다.
const int& unRef2 = 5;     // 변경 못하도록 const를 붙인다면 가능하다.

string& str1 = getString();  // 에러! 임시 객체는 변경할 수 없다.
const string& = getString(); // 변경 못하도록 const를 붙인다면 가능하다.

레퍼런스는 처음 가리키는 대상을 계속해서 가리킨다. 그 값은 변해도 방향은 바뀌지 않는다.

int x = 3; y = 4;
int& xRef = x;
xRef = y

위의 경우에는 xRef가 y를 가리키게 되는 것이 아니다. 가리키고 있는 x는 유지하되 y이 x에 대입된다.

특징

  • 생성과 동시에 초기화 해야한다.
  • 이름 없는 값에 대해서는 레퍼런스 생성이 불가능하다.
  • 변경이 불가능하도록 const를 붙인다면 리터럴이나 임시 객체도 레퍼런스 생성이 가능하다.
  • 래퍼런스는 가리키는 대상을 변경할 수 없다.
  • 함수의 매개변수로 자주 사용된다. 인수의 복사본을 만들지 않기 때문이다.

2) 포인터와 레퍼런스

int* intPtr;
int*& intPtrRef = intPtr;

int x = 3;
int& xRef = x;
int* xPtr = &xRef;
  • 포인터를 선언하고, 해당 포인터에 대한 레퍼런스를 선언할 수 있다.
  • 레퍼런스의 주소를 값에 대한 포인터로 사용할 수 있다.
  • 레퍼런스에 대한 레퍼런스는 불가

레퍼런스로 가능한 일을 대부분 포인터로 할 수 있고, 그 반대도 가능하다. 그러나 레퍼런스가 훨씬 안전한데, null값을 가질 수 없고 명시적으로 역참조 할 수도 없기 때문이다. 물론 각각 사용되는 곳이 다르니 상황에 맞추어 사용하자. 잘 모르겠으면 메모리 소유권을 따져보라.

  • 메모리의 해제 책임이 존재 → 포인터 사용
  • 메모리 해제할 일이 없음 → 레퍼런스 사용

3) 클래스와 레퍼런스

class MyClass{
public:
	MyClass(int& ref) : mRef(ref){ /*...*/ }
private:
	int& mRef;

위와 같이 레퍼런스를 멤버로 사용할 수 있다. 초기화가 private에서 초기화가 안된 것 처럼 보이는데, 클래스의 생성자가 작동할 때 생성자 이니셜라이저에서 초기화된다. 본문에서가 아니다!