-
참조와 포인터 차이점, 지역변수 참조반환하지말것!@ 16. 1 ~ 17. 1/면접관련 2017. 1. 4. 19:36
참조만의 특징
1. 초기화가 필요하다
포인터의 경우 무엇을 가리키는지 알 수 없는 것도 만들수 있다.
int *ptr;
하지만 참조의 경우
int &ref; 는 안된다.
2. 가리키는 대상을 변경할 수 없다.
포인터는 도중에 가리키는 대상을 변경할 수 있다.
int a;
int *ptr=&a;
int b;
ptr=&b;
이런식으로 변경이 가능하지만
참조는..
int &ref=a;
ref=b; 이러면 에러다..
3. 첨자를 붙일 수 없으며 숫자도 더할 수 없다.
포인터의 경우
int *ptr=&a;
ptr[3]=2;
ptr+=2; //주소값이 변한다 8byte
이 가능하지만..
참조는..
int &ref=a;
ref[3]=2; // 안된다.
ref+=2;
그냥 a에 2를 더한값이다.
지역변수 참조반환하지 말아야 하는 이유
오늘은 메모리에 관해 좀 재밌는 내용을 설명하겠다.
레퍼런스 변수는 원본과 같은 메모리 공간을 가리킨다고 지난 포스트에 설명했다.
(기억이 나지 않는다면 [제2장] C++ 기본 : Reference 포스트를 참고하시라~)
레퍼런스 변수를 리턴값으로 쓰기 위해선 원본이 메모리상에 보존되어야 한다.
무슨 말인고 하니... 레퍼런스 변수가 가리킨 값(원본)이 사라진다면
레퍼런스 변수 역시 의미가 없어지기 때문이다.
일단 정상적으로 돌아가는 아래 예제를 살펴보자.
#include < iostream >
using namespace std;
int& increment(int &val) // 레퍼런스 변수로 원본을 받음
{
val++;
return val;
}
void main()
{
int n = 10;
int &ref = increment(n); // 파라미터로 레퍼런스 원본으 넘겨줌
cout << "n : " << n << endl;
cout << "ref: " << ref << endl;
}
자... 누구나 예상할 수 있듯이 결과는 11이 출력된다.
왜냐하면 원본 변수 int n 은 레퍼런스 변수가 사용되는 동안 유지되기 때문이다.
10의 값이 함수 안에서 ++ 연산을 통해서 11이 되었고 그것을 출력하였다.
그럼 당연히 반대의 경우도 살펴봐야되지 않겠는가?
지역변수를 레퍼런스 변수로 리턴하는 경우를 살펴보자.
#include < iostream >
using namespace std;
int& function()
{
int val=10; // 지역변수가 원본이 되었다
return val;
}
int& function2() // 임의로 추가한 두번 째 함수
{
int val2=20;
return val2;
}
void main()
{
int &ref = function(); // 레퍼런스 변수 ref의 원본은 function()의 지역변수이다
int &ref2 = function2();
cout << ref << endl;
}
자... 무엇이 출력될 것 같은가? - 주의 : 원본 소스에서 function2()가 추가되었다 -
언뜻 보면 ref는 function()의 지역변수 int val = 10; 로부터 참조하였으니 10을 출력할 것 같다.
하지만 이 소스는 20을 출력한다!
ref는 분명 function()에서 값을 받았는데... function2()의 20이 출력된다.
우째 이런 일이...!
자 이제부터 이유를 알아보자.
main()이 실행되면 프로세서에 int ret와 int ret2에 대한 메모리를 할당한다 (총 8바이트)
예를들어 ret가 메모리 8000번에, ret2가 8004번에 할당되었다고 가정한다.
ㅁㅁㅁㅁ ㅁㅁㅁㅁ
(ret) (ret2)
다음 function()이 실행되면 함수 내 지역 변수를 할당하기 위해서 추가적으로 4바이트를 할당한다
그럼 val은 메모리 8008번에 할당된다.
ㅁㅁㅁㅁ ㅁㅁㅁㅁ ㅁㅁㅁㅁ
(ret) (ret2) (val)
이제 ret는 레퍼런스 리턴으로 val의 위치를 참조하게 된다. 이때 가리키는 값은 10 이다.
(지금 cout으로 출력하면 10이 출력된다)
자~ 이제 함수 function()이 종료되고 지역번수 val이 차지하는 메모리공간 8008은 사라진다.
ㅁㅁㅁㅁ ㅁㅁㅁㅁ
(ret) (ret2)
그리고 function2()가 실행되면서 val2의 메모리가 8008에 할당된다.
ㅁㅁㅁㅁ ㅁㅁㅁㅁ ㅁㅁㅁㅁ
(ret) (ret2) (val2)
중요한 점은 ret가 아직도 8008번을 가리키고 있다는 것이다!
val2의 값은 20이 대입되었으니 이제 ret의 값을 출력하면 20이 출력된다.
이러한 이유로 지역변수를 레퍼런스로 리턴할 경우 뜻하지 않은 결과를 초래할 수 있다.
이런 버그는 참 찾기 힘드니 절.대.로. 이렇게 코딩하지 말자!'@ 16. 1 ~ 17. 1 > 면접관련' 카테고리의 다른 글
메서드 오버라이딩의 특수한 경우 (0) 2017.01.04 friend 키워드의 의미? (0) 2017.01.04 void 형 포인터 (0) 2017.01.04 문자열 관련 (0) 2017.01.04 C++ 템플릿의 종류 (0) 2017.01.04