참조자(Reference)

포인터(Pointer)와 같이 변수/상수를 가리키는 방법으로, C에서 없던 C++의 새로운 개념이다.
이번 게시글에선 참조자와 포인터의 비교, 이를 이용한 함수에서 벡터를 인자로 호출할 때의 각 방법에 대해서 다루도록 하겠다.

1. 포인터와 참조자

포인터와 참조자의 차이를 알아보기 위해,
100의 값이 들어있는 int형 변수를 포인터와 참조자 두 방식을 사용해 50으로 바꾸는 코드를 아래에 작성해보았다.

    // 포인터
    int a = 100;
    int* pA = &a;
    *pA = 50;
    cout << a << " " << *pA << endl;

    // 참조자
    int b = 100;
    int& rB = b;
    rB = 50;
    cout << b << " " << rB << endl;
output
    50 50
    50 50

이를 통해 알 수 있는 것은, 참조자는 100이라는 값이 저장되어 있는 메모리에
기존 변수명 b로만 접근하던 것을 rB로도 접근할 수 있다는 것이다.

이러한 방식은 가시적으로 보아도 포인터에 비해서 코드가 훨씬 간결해진다는 것을 알 수 있다.
그러나 참조자를 사용하기 위해선 몇 가지 주의사항을 알아야한다.

  1. 참조자만 단독으로 정의 불가
  2. 참조자는 가리키는 변수를 변경할 수 없다
  3. 참조자의 참조자, 참조자의 포인터, 참조자의 배열은 존재할 수 없다



2. 함수에서 벡터를 인자로 받을 때

참조자와 포인터를 이용해서 main함수에서 선언된 벡터를 인자로 받아,
벡터에 값을 push_back하는 함수들을 코드로 표현해보았다.

#include <iostream>
#include <vector>
using namespace std;

void test1(vector<int> v){ // test1함수 내에서 v 벡터를 생성 후 main함수에서의 vector를 복사한다.
    v.push_back(1); // 벡터에 1을 추가하지만, main함수의 vector 벡터의 값은 변하지 않는다.
    cout << v.size() << endl; // 3 -> v 벡터의 사이즈를 출력
}

void test2(vector<int>* v){ // main함수의 vector를 포인터를 이용해 인자로 넘기는 방식
    v->push_back(2); // main함수에 있는 vector에 2가 추가된다.
}

void test3(vector<int>& v){ // main함수의 vector를 참조자를 이용해 인자로 넘기는 방식
    v.push_back(3); // v가 main함수의 vector와 같은 메모리 공간을 가리킨다. -> main함수의 vector에 3이 추가된다.
}

int main(){
    vector<int> vector = {0, 0};
    test1(vector); // vector 값 추가 x
    test2(&vector); // vector 값 추가 o - 포인터
    test3(vector); // vector 값 추가 o - 참조자
    for (int i : vector){
        cout << i << " ";
    }
    cout << endl;
}
output
    3
    0 0 2 3

위의 코드와 출력 결과를 확인해보면, 참조자와 포인터의 사용법을 간단히 확인할 수 있다.



정리,
참조자는 C++에서 새로 추가된 변수를 가리키는 방법이다.
참조자는 포인터보다 사용할 때 코드가 간결하나, 참조자 사용 시 주의사항을 생각해서 사용하도록 한다.