2025. 4. 18. 10:12ㆍProgramming Language/C++
기존에 우리가 만들었던 changer 함수를 보면
이렇게 구현되어 있는데 여기서 보면 changer함수의 전달인자로는 &를 붙여 주소값을 보내야 되고 changer함수내부에서는 *연산자를 사용해서 값을 가져와 사용해야하는 것과 같이 한 두 가지의 depth를 생각해가면서 개발을 해야만 한다는 불편함이 있다.
이때 레퍼런스라는 것을 사용해서 이걸 해결해줄 수 있다.
1. 레퍼런스
C++에서 레퍼런스(Reference)란 어떤 변수의 별명(alias) 또는 다른 이름이라고 볼 수 있는 개념이다
이미 존재하는 메모리 공간을 새 이름으로 참조하게 되므로, 포인터처럼 별도로 주소를 저장하지 않고도 간접 참조가 가능하다.
레퍼런스를 사용하면 코드의 안전성과 가독성이 높아지고, 특히 함수에서 인자 전달, 반환값 처리, 객체 복사 최소화 등에 유용하게 쓰인다.
1) 레퍼런스의 사용
기본적인 레퍼런스의 선언 방법은
int n = 10;
int& ref = n;
와 같이 사용하고 여기서 ref는 int형 변수 n의 레퍼런스라고 부른다.
레퍼런스는 반드시 선언과 동시에 초기화되어야 하며, 이후 참조 대상을 바꿀 수 없다
2) 레퍼런스의 종류
레퍼런스는 일반 레퍼런스, const 레퍼런스, rvalue 레퍼런스가 존재하고 각각의 사용방법이 조금 다르다.
1. 일반 레퍼런스
일반 레퍼런스는
int n = 10;
int& ref = n;
와 같이 일반 변수에 대한 변수로 등록되어 사용된다.
2. const 레퍼런스
const 레퍼런스는 참조 대상(변수)의 값을 수정하지 않겠다는 의미로, 주로 읽기 전용 접근이 필요할 때 사용한다.
void printValue(const int& value) {
// value = 20; // <- 이렇게 값 변경 불가
std::cout << "값: " << value << std::endl;
}
int main() {
int num = 10;
printValue(num); // 읽기 전용으로 num을 전달
return 0;
}
이렇게 함수로 전달한 num의 값은 읽을수는 있으나 변경할수는 없기에 num이란 변수가 변경되지 않는다는 보장이 된다
3. rvalue 레퍼런스
rvalue 레퍼런스는 임시값(rvalue) 에 참조할 수 있도록 도와주는 레퍼런스 타입으로 이 방식을 사용해서 통해 자원을 이동 시키는 최적화가 가능하다.
int&& rref = 10; // OK
int x = 5;
int&& rref2 = x + 1; // OK (임시 값)
* 특이점
const int& cref = 10;
특이한 점은 const 레퍼런스는 lvalue, rvalue 모두 받을 수 있기에 10도 바인딩 가능하다
하지만 int&는 lvalue만, int&&는 rvalue만 받을 수 있다
또한 기존의 레퍼런스의 경우는 다른 타입에 대해서 초기화가 불가능 한 반면
float f1 = 3.14f;
int& ref = f1; // -- 불가능
const 레퍼런스의 경우는 다른 타입으로 초기화도 가능하다
float f1 = 3.14f;
const int& ref = f1;
이게 가능한 이유는 const 레퍼런스를 선언하면 const 레퍼런스는 변수 자체를 직접 바라보는게 아니라 임시 객체를 만든 후 그걸 가르키기 때문이다.
아래 두 경우에도
동일한 결과를 보여주는 것을 볼 수 있다.
이게 왜 발생하냐면
2. 포인터 대신 사용하는 레퍼런스
이제 가장 위에 작성했던 코드를 레퍼런스로 수정해보자.
이렇게 변경을 했다 실행해보면
이렇게 정상적으로 변경된것을 볼 수 있다.
여기서 const 레퍼런스를 사용해보자면
이렇게 함수의 매개변수로 const 레퍼런스를 등록하면 사용자가 해당 함수로 값을 넘겨 준 후에 해당 함수가 어떤 난리를 치더라도 해서 a와 b의 값이 변경되지 않는다는 장점이 있다.
그리고 내부에서 이 값을 변경하려고 해도
이렇게 변경하지 못함을 알려준다.
3. 레퍼런스를 사용하면서 발생하는 주의 사항
1) 뎅글러 레퍼런스를 주의하자
함수의 return 타입이 레퍼런스의 형태인 경우 return하는 값이 함수 내부에서 만든 지역변수를 던지게 되면 함수가 종료되면서 변수의 할당이 해제되고 이로 인해 return값이 무엇을 가리켜야할지 모르는 상황이 될 수 있으니 이는 포인터에 이어 조심해줘야 하는 부분이다.
2) 구조체의 멤버를 레퍼런스로 반환할때의 활용법
이런 구조체가 정의 되어 있고
함수에서 이 구조체 타입의 변수를 레퍼런스로 받고 이 구조체의 멤버 n을 레퍼런스로 반환한다면
보통은
이렇게 사용하고 함수가 호출된 쪽에서 이 값을 받아 사용할텐데 사실 여기에다가
이렇게 반환되는 값에 값을 할당하는 것도 가능하다.
실행시켜보면
이렇게 변경된 값이 출력되는 것을 볼 수 있다.
이게 어떻게 가능하냐면
이 함수의 반환값이 p.n의 레퍼런스인건데 그러면 결국 이 함수를 call 한 부분
이게 결국 p.n의 레퍼런스로써
서로 같은 의미를 지니게 된다
그렇기에
이 둘이 같은 거라고 보면 된다.
근데 나는 이런 방식을 허용하고 싶지 않다 라고 생각한다면 반환값에 const를 넣어주면
이렇게 수정할 수 없도록 바뀐다.
추후 이 레퍼런스에 대해서는 Operator Overloding을 사용해야 할때 무조건 사용되어야하기 때문에 그 때 조금 더 상세하게 확인해보도록 하자.
'Programming Language > C++' 카테고리의 다른 글
Ch 09. 함수 - 07. 함수 오버로딩 (0) | 2025.04.18 |
---|---|
Ch 09. 함수 - 06. 디폴트 매개변수 (0) | 2025.04.18 |
Ch 09. 함수 - 04. 주소로 전달 (0) | 2025.04.18 |
Ch 09. 함수 - 03. 값으로 전달 (0) | 2025.04.18 |
Ch 09. 함수 - 02. 재귀 함수 (0) | 2025.04.16 |