- 여기서 중요한 것은 포인터와 레퍼런스의 차이를 아는 것
→ C++에서는 포인터와 레퍼런스라는 개념이 등장
- 포인터는 C에도 있던 개념
- 레퍼런스는 C++에서 등장한 개념
포인터와 레퍼런스의 차이는 함수의 매개변수로의 전달 방법으로 알아보자
매개변수를 단순 값 타입로 전달했을 경우 함수에선 단순히 복사된 값을 사용하기 때문에 원본에 접근하지 못함.
만약 포인터 또는 레퍼런스로 전달하면 함수에서도 주소를 통해 원본에 접근하여 값을 읽거나 수정할 수 있도록 해줄 수 있다.
표면적인 차이
포인터 사용 시 다음과 같은 매개변수를 포인터로 주고 함수 호출 시 주소를 전달.
void func(int* ptr) { *ptr *= 2; }
int num = 3;
func(&num); // call by address
→ 함수에선 전달 받은 주소를 통해 주소가 가리키는 메모리 공간에 가서 값을 수정하거나 읽을 수 있게 된다
- 단순한 (주소)값 복사이기 때문에 주소가 가리키는 공간에 접근할 수 있는 것 뿐이지 더블포인터를 쓰지 않는 이상 포인터가 가리키는 대상 자체를 변경할 수는 없다.
레퍼런스
레퍼런스로 전달 시 다음과 같은 매개변수를 참조형 변수로 주고 함수 호출 시 lvalue를 전달한다.
void func(int& a){ a *= 2; }
int num = 3;
func(num); // call by reference
→ 매개 변수에 있는 &연산자는 변수의 주소값을 얻을 때 & 연산자와 다름. 위 함수 처럼 레퍼런스 형태로 변수를 받게 되면 매개변수 a를 통해 num값(원본)접근할 수 있게 된다.
int ptr = &num*
위와 같이 포인터는 포인터 변수 ptr이 stack에 4바이트 공간으로 존재하고, 변수 num의 주소 ptr이 가지고 있는 것이다. 그냥 둘은 서로 다른 변수이고, ptr은 num의 주소를 저장하고 있을 뿐 그 이상 그 이하도 아님. 반면 참조자 ref는 포인터처럼 변수 개념으로 따로 생성되는 것은 아님.
즉 다음과 같이이 포인터 변수와 가리키는 대상의 주소값은 같더라도 포인터 변수의 주소값과 대상의 주소값은 다르다
ptr1 == &num
&ptr1 != &num
하지만 레퍼런스는 동일하다.
ref == num
&ref == &num
쉽게 설명
그러니까 포인터는 자기 자신과 주소값을 넘겨주는 변수가 따로이고 레퍼런스는 그 친구를 그대로 받는 것이라고 생각
어셈블리어를 보면 주소값이 똑같다
→ 겉으로 달라보여도 내부적으로는 똑같다
그러면 등장한 이유?
- 기본적으로 포인터는 주소를 가리키지만 다음과 같이 널을 가리킬 수도 있다.
- 널 포인터를 유효하지 않는 객체라는 NULL의 객체를 가리키는 상수이다.
- 유효하지 않는 공간을 가리키게 되면 에러를 발생시키며 프로그램에 문제를 줄 수 있다.
int* ptr = nullptr;
- 인자에 주소를 담아 포인터로 함수를 호출했다고 가정 → 호출된 함수에선 포인터를 통해 주소가 가리키는 값에 접근 가능.
- 그런데 포인터가 강력한 이유는 전달 받은 주소에 덧셈 뺄셈을 하면서 다른 주소도 접근이 가능함
- 반대로 이 말을 보면 포인터를 통해 할당되지 않은 메모리 공간 또는 다른 용도로 사용되고 있는 메모리 공간에 임의로 접근할 수 있다는 의미.
- 100번지에 절대 없어지면 안 되는 값을 저장해놓았는데 포인터를 통해 실수로 100번지의 값을 건드릴 수 있다는 얘기.
void func(int* ptr) { *(ptr) = 3; *(ptr+1) = 4; *(ptr+2) = 5; } int arr[10]{}; func(arr);
이 두 가지를 없애고 포인터는 그대로 사용할 수 있도록 하는 것이 레퍼런스.
레퍼런스는 어셈블리어에서 살펴본 것과 값이 우변의 주소값을 할당하기 대문에 NULL은 안 된다.
int& ref = NULL; // 불가
레퍼런스는 참조로 전달을 받아도 함수 내에서 절대 원본(a:값이 아닌 대상)을 변경할 수 없다.
void func(int& ref) {}
int a = 3;
func(a);
따라서 다른 메모리 상의 위치에 접근할 수가 없다.
레퍼런스는 포인터를 위험하게 사용하는 경우가 많기 때문에 안전하게 사용할 수 있도록 만든 개념.
포인터와 같이 주소를 통해 원본에 접근하는 핵심적인 기능을 가졌지만, 가리키는 대상, 원본, 주소를 변경하지 못하게 막은 것.
레퍼런스를 사용할 때는 언제임?
→ 가리키는 대상이 절대 변하지 않는다. 변하면 안 된다
이 분의 블로그를 보고 공부했습니다
[C++] 포인터와 레퍼런스(참조)의 차이를 이해해보자
'C++ > C++ 동적 할당, 객체 포인터 할당, 레퍼런스' 카테고리의 다른 글
객체 포인터 배열 할당 (1) | 2023.12.01 |
---|---|
C++의 동적할당 (0) | 2023.11.30 |