C++ 기초개념 2 : reference(참조자)
이글은 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 언어에서 엄청나게 큰 구조체가 있을 때 해당 구조체 변수를 그냥 리턴하면 전체 복사가 발생해야 해서 시간이 오래걸리지만, 해당 구조체를 가리키는 포인터를 리턴한다면 그냥 포인터 주소 한 번 복사로 매우 빠르게 끝납니다.
마찬가지로 레퍼런스를 리턴하게 된다면 레퍼런스가 참조하는 타입의 크기와 상관 없이 딱 한 번의 주소값 복사로 전달이 끝나게 됩니다. 따라서 매우 효율적이죠! - 모두의 코드 강의중