C++/C++ 동적 할당, 객체 포인터 할당, 레퍼런스

레퍼런스와 포인터

재윤 2023. 11. 30. 17:41
반응형
  • 여기서 중요한 것은 포인터와 레퍼런스의 차이를 아는 것

→ C++에서는 포인터와 레퍼런스라는 개념이 등장

  1. 포인터는 C에도 있던 개념
  2. 레퍼런스는 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

쉽게 설명

그러니까 포인터는 자기 자신과 주소값을 넘겨주는 변수가 따로이고 레퍼런스는 그 친구를 그대로 받는 것이라고 생각

 

 

어셈블리어를 보면 주소값이 똑같다

→ 겉으로 달라보여도 내부적으로는 똑같다

 

그러면 등장한 이유?

  1. 기본적으로 포인터는 주소를 가리키지만 다음과 같이 널을 가리킬 수도 있다.
    1. 널 포인터를 유효하지 않는 객체라는 NULL의 객체를 가리키는 상수이다.
    2. 유효하지 않는 공간을 가리키게 되면 에러를 발생시키며 프로그램에 문제를 줄 수 있다.
    int* ptr = nullptr;
    
  2. 인자에 주소를 담아 포인터로 함수를 호출했다고 가정 → 호출된 함수에선 포인터를 통해 주소가 가리키는 값에 접근 가능.
    1. 그런데 포인터가 강력한 이유는 전달 받은 주소에 덧셈 뺄셈을 하면서 다른 주소도 접근이 가능함
    2. 반대로 이 말을 보면 포인터를 통해 할당되지 않은 메모리 공간 또는 다른 용도로 사용되고 있는 메모리 공간에 임의로 접근할 수 있다는 의미.
    3. 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++에는 포인터(Pointer)와 레퍼런스(Reference)라는 개념이 있다. 포인터는 C 에도 있었던 개념이며 레퍼런스는 C++ 에서 등장한 개념이다. 언뜻 보면 용도가 비슷한데 정확히 어떤 차이점이 있는지,

woo-dev.tistory.com

 

반응형

'C++ > C++ 동적 할당, 객체 포인터 할당, 레퍼런스' 카테고리의 다른 글

객체 포인터 배열 할당  (1) 2023.12.01
C++의 동적할당  (0) 2023.11.30