컴공생의 다이어리
[c++] 참조자(레퍼런스) 본문
참조자의 도입
#include<iostream>
int change_val(int *p){
*p=3;
return 0;
}
int main(){
int number = 5;
std::cout<<number<<std::endl;
change_val(&number);
std::cout<<number<<std::endl;
}
위의 코드를 성공적으로 컴파일을 하면 5와 3이 출력된다.
change_val 함수의 인자 p에 number의 주소값을 전달하여, *p를 통해 number를 참조하여 number의 값을 3으로 바꾸었다.
c언어에서는 어떠한 변수를 가리키고 싶을 땐 반드시 포인터를 사용해야만 했다. 하지만 C++에서는 다른 변수나 상수를 가리키는 또 다른 방법으로 참조자를 제공한다.
#include<iostream>
int main(){
int a=3;
int &another_a=a;
another_a=5;
std::cout<<"a:"<<a<<std::endl;
std::cout<<"another_a:"<<another_a<<std::endl;
return 0;
}
성공적으로 컴파일을 하면 아래와 같은 실행 결과가 출력된다.
a:5
anaother_a:5
코드를 분석해보자!
int a=3;
처음 int형 변수인 a를 정의하고 그 안에 3이란 값을 넣어준다.
int &another_a=a;
그 후에 a의 참조자 another_a를 정의한다. 이 때 참조자를 정하는 방법은, 가리키고자 하는 타입 뒤에 &를 붙이면 된다. 위처럼 int형 변수의 참조자를 만들고 싶을 때는 int &를, float의 참조자를 만들고 싶다면 float &으로 하면 된다. 혹시 int*와 같은 포인터 타입의 참조자를 만들고 싶다면 int*&로 쓰면 된다.
아무튼 another_a는 a의 참조자이다. 이 의미는 another_a는 a의 또 다른 이름이라고 컴파일러에게 알려주는 것이다. 따라서 another_a에 어떠한 작업을 수행하든 이는 사실상 a에 그 작업을 하는 것과 마찬가지이다.
another_a=5;
std::cout<<"a:"<<a<<std::endl;
std::cout<<"another_a:"<<another_a<<std::endl;
따라서 위 처럼 another_a에 5를 대입하면 연결되 a의 값도 5로 변경된다.
참조자와 포인터는 상당히 유사한 개념이라고 할 수 있다. 포인터 또한 다른 어떤 변수의 주소값을 보관함으로써 해당 변수에 간접적으로 연산을 수행할 수 있기 때문이다. 하지만 참조자와 포인터는 몇 가지 중요한 차이점이 있다.
참조자와 포인터의 차이점
1. 참조자는 반드시 처음에 누구의 별명이 될 것인지 지정해야 한다.
- 참조자는 정의 시에 반드시 누구의 별명인지 명시해야 한다. 아래와 같이 누구의 별명인지를 명시해야 한다.
int & another_a = a;
- 반면 포인터의 경우, 아래와 같이 변수 선언만 해도 전혀 문제가 없다.
int *p;
2. 참조자가 한 번 별명이 되면 절대로 다른 이의 별명이 될 수 없다.
- 참조자가 한 번 어떤 변수의 참조자가 되버리면, 더이상 다른 변수를 참조할 수 없게 된다.
int a=10;
int &another_a=a;
int b=3;
another_a=b; //?
위의 코드를 살펴보면 another_a는 a의 참조자로 선언이되었다. 마지막 부분의 another_a=b의 의미는 무엇일까? another_a가 b의 참조자라고 생각한다면 틀렸다. another_a가 참조하는 a에 b의 값을 대입한다는 의미이다. 사실상 a=b와 같은 의미이다.
참고로 아래와 같이 &another_a=b는 가능할까라고 생각하는 사람도 있을 것이다. 결론부터 말하자면 불가능하다. 아래 문장은 &a=b가 되어서 말이 안된다.
&another_a=b;
- 반면 포인터는 가리키는 대상을 자유롭게 바꿀 수 있다.
int a=5;
int *p=&a; //p는 a를 가리킨다.
int b=3;
*p=b; //p는 a를 버리고 b를 가리킨다.
3. 참조자는 메모리 상에 존재하지 않을 수도 있다.
포인터의 경우, 아래와 같이 포인터 p를 정의하면 p는 당당히 메모리 상에서 8바이트(32비트 시스템에서는 4바이트)를 차지하게 된다.
int a=5;
int *p=&a;
하지만, 참조자의 경우를 생각해보자. 컴파일러의 입장에서 another_a를 위해서 메모리 상에 공간을 할당할 필요가 있을까? 그렇지 않다. 이유는 another_a가 스이는 자리는 모두 a로 바꿔치기 하면 되기 때문이다. 따라서 이 경우 참조자는 메모리 상에 존재하지 않게 된다.
int a=5;
int &another_a=a;
물론 그렇다고 해서 항상 메모리에 존재하지 않는 것은 아니다.
'Development > C & C++' 카테고리의 다른 글
[c++] 메모리 할당과 해제 (0) | 2020.12.18 |
---|---|
[c++] 배열의 레퍼런스 (0) | 2020.12.17 |
[c++] 상수에 대한 참조자 (0) | 2020.12.17 |
[c++] 함수 인자로 레퍼런스 받기 (0) | 2020.12.17 |
[c++] 이름 공간(namespace) (0) | 2020.11.19 |