참조 변수 (Reference variable)
C언어에서 일반 변수와 포인터 변수에 대해서 학습했는데 변수란 메모리 공간에 할당된 이름이다. 그 이름을 통해 해당 메모리 공간에 접근한다. C언어에서는 하나의 메모리 공간에 하나의 이름만 부여할 수 있다.
하지만 C++ 에서는 reference 를 선언하게 되면, "이름이 존재하는 공간에 하나의 이름을 더 부여" 할 수 있다.
reference 를 참조 변수 또는 참조자 라고 표현한다. 책에 따라 우리말 명칭이 약간씩 다름을 알자.
reference는 C++에서 지원하는 변수 타입으로 다른 객체 또는 값의 별칭으로 사용된다.
int a(10); // C언어의 int a = 10; 과 같다.
int &ref = a; // 선언 방법은 자료형 &참조변수이름 = 원래변수;
ㅇ non-const 값 참조형은 자료형 뒤에 앰퍼샌드(&)를 사용하여 선언한다.
ㅇ Lvalue는 메모리 주소를 가진 객체이고 Rvalue는 메모리 주소가 없고, 표현식 범위에만 있는 임시 값이다.
ㅇ 참조변수에 대입하는 값은 Lvalue 만 가능하다.
ㅇ 주소 연산자 & 는 Lvalue를 요구하기 때문에 표현식이 Rvalue라면 컴파일 오류가 발생한다.
※ C++에서 모든 표현식은 Lvalue 또는 Rvalue 이다. ㅇ 단항 & (address-of) 연산자는 그것의 피연산자로 Lvalue 를 필요로 한다. int n, *p; ㅇ 포인터 p 는 항상 객체를 가리킨다. 그러므로 *p 는 Lvalue 이다. int a[N]; *(p + 1) = 4; // Fine. (p+1) 는 Rvalue ㅇ 리턴타입이 오직 참조인 경우에만 함수 호출은 Lvalue 이다. 출처 : http://jeremyko.blogspot.com/2012/08/lvalue-rvalue.html 에서 필요 부분만 발췌 원출처 : https://www.codeproject.com/Articles/313469/The-Notion-of-Lvalues-and-Rvalues |
참조자는 별도의 메모리를 할당하지 않고 변수 선언문에서 초기화에 사용한 변수의 메모리를 참조하여 사용한다. 이러한 이유로 참조자는 선언과 동시에 무조건 변수를 참조하도록 해야 한다.
null 값을 저장할 수 있는 포인터와 다르게, null 참조 같은 것은 없다.
배열의 요소는 변수로 간주되어 참조자 선언이 가능하다.
int arr[3] = { 1, 2, 3};
int &ref1 = arr[0];
int &ref2 = arr[1];
int &ref3 = arr[2];
포인터 변수도 변수이기 때문에 참조자의 선언이 가능하다.
int num = 10;
int *ptr = #
int &ref = num;
int *(&pref) = ptr;
예제1.
#include <iostream> // 포인터 연산을 할 필요가 없으므로 보다 안정적이다. // 함수의 호출 형태를 구분하기 어렵다. // 자료형 &참조변수이름 = 원래변수; // food의 메모리 주소와 reference 메모리 주소가 동일하고, 할당한 포인터 주소가 동일함을 확인할 수 있다. // 하지만 포인터 자체 주소는 다르다는 것도 알 수 있다. cout << &food << endl; // food 값의 메모리 주소 출력 |
예제2
#include <iostream> |
원본 변수 n 은 참조 변수 ref가 사용되는 동안 유지되기 때문에 결과는 11을 반환한다.
반환이 int& 인데 int 로 하면 어떻게 되는지 변경해보라.
같은 주소를 사용하는지 다른 주소를 사용하는지 확인이 될 것이다.
그런데 return 받는 변수가 지역변수라면 어떤 결과가 발생할까?
https://www.youtube.com/watch?v=Bko1OoExWhg&t=319s 동영상 강좌를 참조해서 들어보자.
#include <iostream> cout << " sum address : " << &sum << endl; |
실행 결과
C++ 에서 함수 처리 return 메커니즘은 return 값을 임시 저장 공간에 복사한 후 그것을 return하는 방식이다.
하지만 return by reference 형식을 사용할 경우 임시 저장공간을 사용하지 않고 호출 함수가 return값에 직접 접근을 하게 된다.
main()이 실행되면서 int ref1 과 int ref2 에 메모리를 각각 4 바이트씩 할당한다.
그 다음에 CalSum() 함수가 실행되면 함수 내 지역변수 int sum 에 메모리를 할당하기 위해 추가적으로 4바이트를 할당한다.
CalSum(1, 20) 의 결과 리턴으로 210을 반환한다. 그런 다음에 CalSum()함수가 종료되고, 지역변수 sum 이 차지하는 메모리 공간은 사라진다.
CalSum(1, 10)을 실행하면서 다시 지역변수 sum 이 차지하는 메모리 공간을 할당한다. 할당된 공간의 메모리 주소는 동일한 주소 공간을 차지한다는 걸 위 실행 결과에서 확인할 수 있다.
여기서 ref1 도 동일한 메모리 주소를 참조하고 있기 때문에 결과는 210이 아닌 55를 반환한다.
그 이유는 함수 내의 로컬 변수의 reference를 참조할 경우, local 변수는 함수 종료시 파괴되지만 ref1의 경우 reference 자체를 계속해서 참조하고 있기 때문이다.
따라서 지역변수를 reference 로 return 하는 경우 원하지 않는 결과를 초래할 수 있으므로 코딩시 주의해야 한다.
'C++ > C++ 문법' 카테고리의 다른 글
C++ namespace(네임스페이스) (0) | 2019.11.22 |
---|---|
C++ 오버로딩 (0) | 2019.11.22 |
C++ 입력(cin) 과 출력(cout) (0) | 2019.11.21 |
C언어 중첩 구조체(Nested structure) (0) | 2019.11.20 |
C언어 구조체(Struct) 이해 및 C++ 구조체 예제 (0) | 2019.11.19 |