개발공부/모두의 코드 C++

C++ 기초개념 2 : reference(참조자)

수박 서리 2022. 11. 14. 18:08

이글은 c++를 복습하기 위해 모두의 코드 https://modoocode.com/ 있는 강의 글을 정리 한 것입니다.

 

참조자의 도입

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

C 언어에서는 어떠한 변수를 가리키고 싶을 땐 반드시 포인터를 사용해야만 했습니다. 그런데 C++ 에서는 다른 변수나 상수를 가리키는 방법으로 또 다른 방식을 제공하는데, 이를 바로 참조자(레퍼런스 - reference) 라고 부릅니다.

 

 

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

참조자는 타입뒤에 &를 붙이면 됨.

 

int 형 변수의 참조자를 만들고 싶을 때에는 int& 를, double 의 참조자를 만드려면 double& 로 하면 됩니다. 심지어 int* 와 같은 포인터 타입의 참조자를 만드려면 int*& 로 포현

 

어떻게 보면 참조자와 포인터는 상당히 유사한 개념입니다. 포인터 역시 다른 어떤 변수의 주소값을 보관함으로써 해당 변수에 간접적으로 연산을 수행할 수 있기 때문이죠. 하지만 레퍼런스와 포인터는 몇 가지 중요한 차이점이 있습니다.

1.레퍼런스는 반드시 처음에 누구의 별명이 될 것인지 지정해함

2.레퍼런스가 한 번 별명이 되면 절대로 다른 이의 별명이 될 수 없다.

 

상수에 대한 참조자

#include <iostream>

int main() {
  int &ref = 4;

  std::cout << ref << std::endl;
}

실핼시켜보면  아래 처름 컴파일 오류가 보임

error C2440: 'initializing' : cannot convert from 'int' to 'int &'

이유는 바로 4가 리터럴 상수인데 이걸 래퍼런스로 참조한다면 상수의 값을 바꾼다는 말이기 때문에 

상수를 래퍼런스 하는 것은 불가능 

 

 

 

레퍼런스의 배열과 배열의 레퍼런스

C++ 표준안을 보면 아래처럼 작성되어있다.

레퍼런스의 레퍼런스,레퍼런스의 배열, 레퍼런스의 포인터는 존재할 수 없다.
int a, b;
int& arr[2] = {a, b};

C++ 상에서 배열이 어떤 식으로 처리되는지 생각해봅시다. 문법 상 배열의 이름은 (arr) 첫 번째 원소의 주소값으로 변환이 될 수 있어야 합니다. 이 때문에 arr[1] 과 같은 문장이 *(arr + 1) 로 바뀌어서 처리될 수 있기 때문에 

주소값이 존재한다라는 의미는 해당 원소가 메모리 상에서 존재한다 라는 의미

하지만 래퍼런스는 특별한 경우가 아닌 경우 메모리상에서 공간을 차지하지 않는다. 

 

 

하지만 배열들의 레퍼런스는 가능하다.

int arr[3] = {1, 2, 3};
int (&ref)[3] = arr;

위 코드의 의미는 ref[0] 부터 ref[2] 가 각각 arr[0] 부터 arr[2] 의 레퍼런스가 되는것을 표현되기 때문에 가능

 

 

레퍼런스를 리턴하는 함수

int function() {
  int a = 2;
  return a;
}

int main() {
  int b = function();
  return 0;
}

위 코드는 에러가 발생함  why?

functuin() 함수의 a라는 변수는 지역변수이기 때문에 return과 함께 사라지기 때문에

이런 경우를  (Dangling reference)댕글링 래퍼런스라고 함

 

int& function(int& a) {
  a = 5;
  return a;
}

int main() {
  int b = 2;
  int c = function(b);
  return 0;
}

이 코드는 가능 why? 매개변수로 받은 b라는 객체가 아직 살아있기 때문에

 

이렇게 참조자를 리턴하는 경우의 장점이 무엇일까?

C 언어에서 엄청나게 큰 구조체가 있을 때 해당 구조체 변수를 그냥 리턴하면 전체 복사가 발생해야 해서 시간이 오래걸리지만, 해당 구조체를 가리키는 포인터를 리턴한다면 그냥 포인터 주소 한 번 복사로 매우 빠르게 끝납니다.

마찬가지로 레퍼런스를 리턴하게 된다면 레퍼런스가 참조하는 타입의 크기와 상관 없이 딱 한 번의 주소값 복사로 전달이 끝나게 됩니다. 따라서 매우 효율적이죠!   - 모두의 코드 강의중