컴공생의 다이어리

[c++] 참조자(레퍼런스) 본문

Development/C & C++

[c++] 참조자(레퍼런스)

컴공 K 2020. 11. 19. 06:06

참조자의 도입

#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;

물론 그렇다고 해서 항상 메모리에 존재하지 않는 것은 아니다.

 

 

 

modoocode.com/312

 

씹어먹는 C++ 강좌 - PDF 파일

 

modoocode.com

728x90

'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
Comments