C++에서 활용되는 참조자 (reference)에 대해서 알아보도록 하겠다.
[C++] 참조자 (reference)의 정의 및 사용법
참조자 (reference)의 정의
C언어에서 변수를 가리키는 것으로 포인터를 사용한다.
예를 들어 아래와 같이 포인터 변수 p를 선언하고 변수 a를 가리키게 하고 가리키는 값인 *p를 출력하면 3이 출력된다.
int main(void) {
int *p;
int a = 3;
p = &a;
std::cout << *p << std::endl;
}
참조자는 포인터 변수와 비슷하게, C++ 에서 활용되는 변수를 가리키는 방법이다.
아래처럼 int& ref = value; 와 같이 ref라는 참조자가 value를 가리키도록 한다. ref는 value를 가리키는 별명 같은 것이다.
int value;
int& ref = value;
참조자 (reference)의 사용법
내가 가리키고 싶은 변수가 있고, 그 변수의 별명을 ref 라고 지정하고 ref를 출력하는 코드이다. 포인터와는 다르게 * 같은 별도의 기호를 붙임이 않고도 ref 자체만으로도 a처럼 그대로 출력하면 된다. 즉 ref 가 a 인 셈이다. 이게 가능한 이유는 참조자는 단순히 별명 같은 것이고, 새로운 메모리를 할당하는 것이 아니라 컴파일 시에 ref와 a가 동일하게 취급되기 때문이다.
int main(void) {
int a = 3;
int& ref = a;
std::cout << ref << std::endl;
}
아래는 함수의 인자로 전달하는 경우의 예시이다. 포인터를 사용하는 경우와 비교하기 위해 두 가지 함수를 만들어 보았다.
add_one_reference는 인자로 참조자를 받고 add_one_pointer는 인자로 포인터 변수를 받는다. 어차피 인자에는 * 혹은 & 이 붙어야 하는 것은 똑같지만 함수 내에서 값을 접근할 때 참조자는 그대로 사용하면 되지만 포인터는 * 를 붙여서 접근해야 한다. 또한 main 함수에서 호출할 때에 포인터는 변수 a에 &를 붙여서 주소값을 넘겨주어야 하지만 참조자의 경우는 그냥 넘겨주면 된다. 참조자가 훨씬 깔끔하고 직관적이다.
#include <iostream>
void add_one_reference(int& input) {
input++;
}
void add_one_pointer(int* input) {
*input = *input + 1;
}
int main(void) {
int a = 3;
add_one_pointer(&a);
std::cout << a << std::endl;
add_one_reference(a);
std::cout << a << std::endl;
}
참조자(reference) 사용 시 주의 사항
1. 참조자는 새로운 변수가 아니라 별명에 불과하다는 사실을 제일 먼저 인지해야 한다.
2. 참조자는 선언과 동시에 초기화가 되어야 한다. 1번에서 말했다 시피 별명에 불과한데, 별명의 주체가 없는 null 별명은 존재할 수 없는 것이다.
3. 참조자는 한 번 지정이 되면 참조하는 대상을 변경할 수 없다. 포인터 변수처럼 이렇게 저렇게 바꿔가면서 사용하는 용도가 아니다. 참조자에 다른 변수를 지정한다면 그것은 원래 가리키던 값의 변수를 변경하는 것이 된다.
int main(void) {
int a = 3;
int& ref = a;
std::cout << ref << std::endl; // ref 츌력결과 : 3
int b = 5; // 새로운 b 등장
ref = b; // ref 를 b를 가리키도록 함??
// 아니다. ref는 a와 같으므로 a = b 가 되어 a 값을 5로 변경한다.
std::cout << ref << std::endl; // ref 출력결과 : 5
// b를 가리키도록 했으니 5가 출력되었나?? 아니다. ref인 a가 위에서 5로 변경되었기 때문이다.
std::cout << a << std::endl; // a 출력결과 : 5
}
4. Call by value와 잘 구분해서 사용해야 하면 헷갈리면 안된다. 포인터를 사용하면 Call by value와 Call by reference 가 얼핏 봐도 구분이 되지만 참조자를 사용하면 실수할 수도 있으니 조심해야 한다.
결론
참조자는 간단한 듯 하면서도 헷갈리는 부분이 있다. 포인터와의 차이점을 명확하게 이해하고 넘어가는게 좋은 것 같다. 코드의 간결성 때문에 C++에서 실제로 굉장히 많이 사용되고 있기 때문이다.
'개발 > C, C++' 카테고리의 다른 글
[C++] class 생성자에서 explicit 키워드의 의미 (0) | 2023.09.05 |
---|---|
[C++] STL 컨테이너 Set과 Map 활용법과 차이점 (0) | 2023.09.02 |
[C++] STL 컨테이너 Vector 의 용도와 특징, 사용 예제 (0) | 2023.09.01 |
[C++] 생성자에서 virtual 가상 함수 호출하는 경우의 문제 (0) | 2023.08.11 |
[C++] 복사 생성자(Copy Constructor) 의 이해 및 활용 (1) | 2023.07.27 |