레퍼런스란?
C++에서 제공하는 레퍼런스(참조)를 사용하면 기존 변수에 새 이름을 지정할 수 있다.
int x = 42;
int& xReference = x;
변수의 타입 뒤에 &를 붙이면 그 변수는 레퍼런스가 된다.
일반 변수와 같지만 내부적으로는 원본 변수에 대한 포인터로 취급한다.
일반 변수 x와 레퍼런스 변수 xReference는 모두 같은 값이다.
1. 레퍼런스 전달 방식
함수에 전달한 변수는 값 전달 방식으로 처리한다.
함수의 매개변수에 정수를 전달하면 함수 안에는 그 정수의 복제본이 전달된다.
그래서 함수 안에서 원본 변수의 값을 변경할 수 없다.
C에서는 스택 변수에 대한 포인터를 자주 사용했는데,
이런 방식을 사용하면 다른 스택 프레임에 있는 원본 변수를 수정할 수 있다.
이러한 포인터를 역참조하면 그 포인터가 현재 스택 프레임을 가리키지 않더라도
함수 안에서 그 변수가 가리키는 메모리의 값을 수정할 수 있다.
그러나 이 방식은 포인터 연산이 많아져서 간단한 작업이라도 코드가 복잡해진다
C++에서는 값 전달 방식보다 뛰어난 레퍼런스(참조) 전달 방식을 제공한다.
이 방식을 사용하면 매개변수가 포인터값이 아닌 레퍼런스로 전달된다.
void addOne(int i)
{
i++; // 복제본이 전달됐기 때문에 원본에는 아무런 영향을 미치지 않는다.
}
void addOne(int& i)
{
i++; // 원본 변수가 변경된다.
}
첫 번째 함수는 매개변수가 값으로 전달돼 함수 안에서는 그 값의 복제본을 조작하기 때문에 원본 변수는 변하지 않는다.
두 번째 함수는 레퍼런스로 전달되기 때문에 원본 변수의 값도 변경된다.
정수 타입에 대한 레퍼런스를 받는 addOne() 함수를 호출하는 문장을 작성하는 방식은
그냥 정수 값을 받는 함수를 호출할 때와 똑같다.
int myInt = 7;
addOne(myInt);
레퍼런스로 전달하는 버전에 리터럴을 지정하면 컴파일 에러가 발생한다.
addOne(7); // 컴파일에러 발생
2. const 레퍼런스 전달 방식
const 레퍼런스의 가장 큰 장점은 성능이다.
레퍼런스로 전달하면 원본에 대한 포인터만 전달되기 때문에 원본 전체를 복제할 필요가 없다
const 레퍼런스로 전달하면 복제되지도 않고 원본 변수가 변경되지도 않는 장점이 있다.
다음 코드는 std::string을 함수에 const 레퍼런스로 전달하는 예이다.
#include <iostream>
void printString(const std::string& myString)
{
std::cout << myString << std::endl;
}
int main()
{
std::string someString = "Hello World";
printString(someString);
printString("Hello World"); // 리터럴을 전달해도 된다.
return 0;
}
함수에 객체를 전달할 때 값으로 전달하기보다는 const 레퍼런스로 전달하는 것이 좋다.
그러면 불필요한 복제 작업을 피할 수 있다.
전달할 객체를 함수 안에서 수정하려면 non-const 레퍼런스로 전달해야 한다.
'💻프로그래밍 내용 정리 > C++17' 카테고리의 다른 글
[C++ 1.2.6] 타입 추론(auto, decltype) (0) | 2022.08.16 |
---|---|
[C++ 1.2.5] 익셉션(exception(예외)), throw 구문, catch/try 구문 (0) | 2022.08.16 |
[C++ 1.2.3] Const의 다양한 용도 (0) | 2022.08.16 |
[C++ 1.2.2] 스택과 힙, 포인터와 동적 메모리, 역참조, 배열 포인터, 널 포인터 상수(NULL), 스마트 포인터(unique_ptr, shared_ptr) (0) | 2022.08.16 |
[C++ 1.2.1] C++의 스트링 (0) | 2022.08.16 |