KoreanFoodie's Study

C++ 기초 개념 2 : 참조자(레퍼런스) 본문

Tutorials/C++ : Beginner

C++ 기초 개념 2 : 참조자(레퍼런스)

GoldGiver 2021. 12. 20. 13:31


참조자 (레퍼런스)

레퍼런스(reference)는 & 기호를 이용해서 표기한다.

#include <iostream>

int main() {
    int a = 3;
    int& another_a = a;
}

 

참조자는 별명, 즉 또다른 이름이다. 레퍼런스는 반드시 정의 시 누구의 별명이 될 것인지 지정해야 한다.

또한, 레퍼런스가 한 번 별명이 되면 절대로 다른 이의 별명이 될 수 없다!

 

int a = 10;
int& another_a = a;

int b = 3;
another_a = b;

제일 마지막 줄은, 실제로 "a=b"와 같은 의미를 지닌다. 또한, 레퍼런스는 메모리 공간 속에 존재하지 않을 수도 있다. 이는 레퍼런스를 위해 새로운 공간을 할당할 필요가 없을 수도 있다는 것이다.

 

 

참조자의 참조자?

int a = 1;
int& b = a;
int& c = b;

c = 2;

위의 경우에, "c=2;" 를 실행하면 a, b, c의 값이 전부 2로 바뀐다. 셋 모두 같은 곳을 가리키고 있기 때문이다!

또한, c 가 b를 가리키기 위해 && 같은 식으로 사용할 필요가 없다. 별명의 별명이 아닌, 별명을 붙여주는 작업이기 때문이다.

 

 

상수에 대한 참조자

#include <iostream>

int main() {
    int& ref = 4; // error : 만약 리터럴을 레퍼런스로 받으면?
   		  //리터럴의 값을 바꾸는 말도 안되는 행위가 가능해짐
    
    const int& ref = 5; // 이건 가능!    
}

 

 

레퍼런스의 배열과 배열의 레퍼런스

int a, b;
int& arr[2] = {a, b}; // arrays of references are illegal

레퍼런스의 배열은 불가능하다. 주소값이 존재한다는 의미는 해당 원소가 메모리 상에서 존재한다는 의미이지만, 레퍼런스는 특별한 경우가 아닌 이상 메모리 상에서 공간을 차지하지 않는다.

 

하지만 배열들의 레퍼런스는 가능하다!

int arr[3] = {1, 2, 3};
int(&ref)[3] = arr;

ref[0] = 4;
ref[1] = 5;
ref[2] = 6;

두번째 줄에서 ref가 arr를 참조하고 있다. 포인터와는 다르게 배열의 레퍼런스의 경우 참조하기 위해 반드시 배열의 크기를 명시해야 한다.

 

 

레퍼런스를 리턴하는 함수

 

지역 변수의 레퍼런스를 리턴?

다음과 같은 함수가 있다고 하자.

int& function() {
   int a = 2;
   return a;
}

int main() {
    int b = function();
    return 0;
}

위와 같은 상황에서, b가 function( )의 리턴 값(여기서는 참조 타입)을 받는 과정에서 에러가 발생한다.

int b = function( )은 실제로는 다음과 같다.

int& ref = a;

// 근데 a가 사라짐
int b = ref; // ??

function( )이 리턴하면서 a라는 지역변수를 삭제하기 때문에, 메모리 상에서는 별명인 ref만 남고, 별명이 가리키는 값인 a가 사라진 상태가 되는 것이다. 

이와 같이 레퍼런스는 있는데 원래 참조하던 것이 사라진 레퍼런스를 댕글링 레퍼런스(Dangling Reference)라고 한다.

 

외부 변수의 레퍼런스를 리턴?

그렇다면 아래와 같은 경우는 어떨까?

int& function(int& a) {
    a = 5;
    return a;
}

int main() {
    int b = 2;
    int c = function(b);
    return 0;
}

위의 경우, function이 참조자를 리턴하지만, function이 리턴한 참조자는 아직 살아있는 변수인 b를 계속 참조한다. c = 5라는 코드처럼 동작하게 된다.

 

참조자가 아닌 값을 리턴하는 함수를 참조자로 받기

int function() {
    int a = 5;
    return a;
}

int main() {
    int& c = function();
    return 0;
}

위와 같은 코드는 에러가 발생한다. 왜냐하면, int& c = 5; 와 동치이기 때문이다. (Dangling Reference)

하지만 중요한 예외 규칙이 있는데, 그건 바로 const를 사용할 때이다.

int function() {
    int a = 5;
    return a;
}

int main() {
    const int& c = function();
    return 0;
}

값이라도, const & 타입으로 rvalue값을 받으면, 수명이 연장된다. 즉, 상수 레퍼런스로 리턴값을 받으면 된다.

 
Comments