참조자란
#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;
}
C에는 변수를 지정할 때 포인터만을 사용했다면, c++에서는 참조자(레퍼런스)가 등장했습니다.
레퍼런스의 특징
- 선언할 때 반드시 누구의 참조자인지 명시해야만 한다.
- 한번 지정이 되면 다른것의 참조자가 될수가 없다.
- 레퍼런스는 메모리상에 존재하지 않을 수도 있다.
레퍼런스의 레퍼런스,레퍼런스의 배열, 레퍼런스의 포인터는 존재할 수 없다.
- 배열들의 레퍼런스는
int arr[3] = {1, 2, 3};
int (&ref)[3] = arr;
같이 사용이 가능하다.
- 상수는 상수 참조자를 써야하고 다음과 같이
const int &ref = 4;
사용된다.
- 지역 변수의 레퍼런스를 리턴하는 것은 어떤 상황에서도 금지되어있다. 댕글링 레퍼런스를 발생시켜서 오류가 발생하고, 제대로 사용하려면 외부변수의 레퍼런스를 리턴해야한다.
사용법
참조자를 정하는 방법은 가리키고 하는 타입 뒤에 &를 붙히면 된다.
즉 int
같은 경우는 int &
로 double
같은 경우는 double &
로 하면 됩니다.
1. 레퍼런스는 정의 시에 반드시 누구의 별명인지 명시 해야 합니다.
따라서 int& another_a;
같은 문장은 불가능합니다.
다만 함수 인자로 레퍼런스 타입을 사용하는 것은 가능하다.
2. 레퍼런스는 한번 별명이 되면 다른이의 별명이 될 수가 없습니다.
3. 레퍼런스는 메모리상에 존재하지 않을 수 있다.
존재하지 않는경우
int a = 10;
int &another_a = a;
이런식으로 생긴 경우가 할당하지 않는 경우인데 컴파일러가 모든 another_a부분을 a로 바꿔서 사용하면 된다.
존재하는 경우
함수의 매개변수를 레퍼런스로 받을때 매개변수로 전달할 변수의 주소값이 새로운 메모리 공간(스택)에 저장되고 포인터처럼 그 메모리 공간을 레퍼런스가 사용하는 형태이다.
4. 레퍼런스의 레퍼런스,레퍼런스의 배열, 레퍼런스의 포인터는 존재할 수 없다.
int& arr[2] = {a, b};
다음과 같은 코드는 안된다.
왜냐면 c++에서 배열을 처리하는 방식은 문법 상 배열의 이름은 (arr
) 첫 번째 원소의 주소값으로 변환이 될 수 있어야 합니다.
이 때문에 arr[1]
과 같은 문장이 *(arr + 1)
로 바뀌어서 처리될 수 있기 때문이죠.
주소값이 존재한다라는 의미는 해당 원소가 메모리 상에서 존재한다.라는 의미와 같습니다. 하지만 레퍼런스는 특별한 경우가 아닌 이상 메모리 상에서 공간을 차지 하지 않습니다.
5. 배열들의 레퍼런스
#include <iostream>
int main() {
int arr[3] = {1, 2, 3};
int(&ref)[3] = arr;
ref[0] = 2;
ref[1] = 3;
ref[2] = 1;
std::cout << arr[0] << arr[1] << arr[2] << std::endl;
return 0;
}
이차원 배열의 경우
int arr[3][2] = {1, 2, 3, 4, 5, 6};
int (&ref)[3][2] = arr;
6. 상수 참조자
#include <iostream>
int main() {
int &ref = 4;
std::cout << ref << std::endl;
}
다음과 같은 코드는 컴파일러가 에러를 출력한다.
상수(리터럴 값)를 일반적인 참조자가 참조하는 것은 금지된다.
다음과 같이 const int &ref = 4;
상수 참조자로 선언한다면 리터럴 값도 참조할 수가 있다.
7. 댕글링 레퍼런스
지역변수의 레퍼런스를 리턴하는 것은 댕글링 레퍼런스를 발생시키기 때문에 사용할 수 없다.
오류코드
int& function() {
int a = 2;
return a;
}
int main() {
int b = function();
b = 3;
return 0;
}
외부변수의 레퍼런스 리턴
int& function(int& a) {
a = 5;
return a;
}
int main() {
int b = 2;
int c = function(b);
return 0;
}
다음과 같이하면 가능하다.
또한 함수에서 참조자로 리턴을 하고 값 타입으로 받게되면 그 값이 복사가 된다.
8. 참조자가 아닌 값을 리턴하는 함수를 참조자로 받기
오류코드
int function() {
int a = 5;
return a;
}
int main() {
int& c = function();
return 0;
}
만약 다음과 같은 코드를 사용하면 지역변수를 리턴해버려서 지역변수의 메모리를 함수를 빠져나가자마자 사라지게 되서 즉시 댕글링 레퍼런스가 됩니다.
다만 C++에서는 상수레퍼런스를 사용하면 이것을 받을 수 있도록 했습니다.
#include <iostream>
int function() {
int a = 5;
return a;
}
int main() {
const int& c = function();
std::cout << "c : " << c << std::endl;
return 0;
}
상수 레퍼런스로 리턴값을 받게 되면 해당 리턴값의 생명이 연장됩니다. 그리고 그 연장되는 기간은 레퍼런스가 사라질 때 까지 입니다.
Uploaded by N2T
'CPP' 카테고리의 다른 글
[c++개념공부]동적할당과 class (0) | 2023.01.27 |
---|---|
[c++개념공부] 생성자 초기화리스트, static 변수 함수, 레퍼런스 리턴 함수, this (0) | 2023.01.27 |
[CPP함수 사용법]setfill 함수와 setw함수 사용법 (0) | 2023.01.15 |
[CPP 모듈 고민]SEARCH에서 출력 순서 (0) | 2023.01.15 |
[Cpp 개념공부]__how to user input the noprintable ascii on cin (어떻게 cin에서 none printable를 받을 수 있을까)__ (0) | 2023.01.13 |