C++ 레퍼런스에 대해 정리해보는 시간을 가지자.
사실 정의만 놓고 봐서는 어려운 내용이 아니지만
정확하게 알고가지 않으면 나중에 상당히 혼동될 염려가 있을 것 같다.
이번 포스팅에서 완벽하게 정리하고 가겠다.
1. 레퍼런스란 쉽게 말해서 변수에 하나의 이름을 더 붙여주는 것. 하나의 메모리 공간에 여러 이름을 붙여줄 수 있다.
& 연산자는 포인터에 주소값을 전달하기 위해 사용할 수 있고
레퍼런스 선언을 위해 사용할 수 있다.
ex)
int a = 10;
int *ptr = &a;
int &ref = a;
변수란? 메모리 공간에 할당된 이름 --> 레퍼런스는 그러한 이름에 또 다른 이름을 붙여준다.
--> 그 이름으로도 변수를 원래대로 사용할 수 있다.
int i = 5;
int &j =i;
선언과 동시에 초기화가 되어야 하며
선언된 후에는 원래 변수와 완전 똑같이 사용 가능하다.
이름이 존재하지 않는 대상을 레퍼런스로 선언할 수 없다. (ex 상수)
int fct(){
int val = 20;
int &ref = val;
return ref;
}
--> int형 레퍼런스를 int형으로 반환해도 문제없다! --> 레퍼런스는 완전히 똑같은 것으로 생각하면 된다.
--> 만들어지는 방식만 차이가 날 뿐 똑같다.
반대로
int& Get(int& x){ return x; }
int main(){
int _x = 10;
int y = Get(_x); ---> Get은 레퍼런스를 리턴받아서 바로 변수에 대입. --> 레퍼런스는 변수와 똑같이 사용가능하기 때문
}
------------------------------------------------------------------------------ex2
int i = 0;
int &ref1 = i;
int &ref2 = ref1;
--> i에 ref1 ,ref2라는 이름을 붙여주고 있다. (하나의 메모리 공간에 이름이3개 --> (C에서는 상상도 못하는 일)
--> 역시 문제 없다.
-------------------------------------------------------------------------------
2. call by value , call by reference
1. 포인터를 이용한 call by reference --> 포인터 연산에 의한 것이기 때문에 위험성이 존재한다.
void swap (int *xxx, int *yyy){
...
xxx++; ---> 이러한 코드가 잘못들어갈 경우 심각한 오류가 생길 수 있다.
...
}
2. 레퍼런스를 이용한 call by reference --> 함수의 호출 형태를 구분하기 어렵다.
void swap (int &xxx, int &yyy){ ... }
int main(){
int a,b;
....
...
swap(a,b); --> a,b 변수가 xxx, yyy 라는 별명으로 함수내에서 적용된다.
--> call by value인지 call by reference 인지 구분이 모호하다.
}
포인터 연산을 할 필요가 없으므로 보다 안정적이다.
3. call by value
void show(int _a){
cout<< _a <<endl;
}
int main(){
int a = 5;
show(a); --> 변수a를 매개변수 _a에 복사하게 된다. --> 전달 내용이 커질 수록 복사량이 많아짐 --> 기능저하
}
void show(int &_a){ ... }
--> 레퍼런스를 이용하면 복사가 일어나지 않는다. --> 성능 향상
--> 레퍼런스를 이용할 경우 함수내에서 데이터가 조작될 가능성이 있다.
void show(const int &_a) { ... } --> 조작될 위험을 방지 (const)
-----------------------------------------------------------------------------------------------
3. 레퍼런스를 리턴하는 함수
int& GetInt(int &val){
return val;
}
int main(){
int n = 10;
int &ref = GetInt(n); -----------> 1. n이라는 메모리 공간에 val이라는 이름을 붙여준다
---> 2. 레퍼런스를 리턴하는 함수이기 때문에 n은 ref라는 이름을 하나 더 갖게 된다. ( n = val = ref )
---> 3. 함수가 종료되면 함수 내의 레퍼런스도 일반 변수와 마찬가지로 스택에서 없어지게 된다. --> (이름만 없어짐, 메모리는 그대로)
---> 4. 결과적으로 n이라는 메모리 공간에 ref라는 이름을 하나 더 가지게 된다. (val은 함수 종료와 함께 없어짐)
}
------------------------------------------------------------------------------------------------------------------------------------
int GetInt(int &val){
...
return val; ------------> int형으로 리턴된다. 위의 경우에 에러가 난다. 왜?? 레퍼런스는 상수에 정의를 할 수 없다!!
}
-------------------------------------------------------------------------------------------------------------------------------------
int& fct(){
int val = 10;
return val;
}
int main(){
int &ref = fct(); ------------> 오류가 난다. 왜?? 함수가 끝나면 val이라는 메모리 공간은 없어지기 때문에
--> 없는 공간에 이름을 붙일 수 없다!
}
--> 지역변수는 레퍼런스로 리턴할 수 없다.
--> 지역객체 또한 레퍼런스로 리턴할 수 없다.
?? 객체 레퍼런스를 리턴하는 함수 대한 이해가 필요함 --> 복사생성자에 해답이 있는 듯 하다
AAA 클래스{
int x,y;
public:
AAA(int _x, int _y) : x(_x), y(_y){};
}
AAA Get(){
AAA temp(3,4);
return temp;
}
int main(){
AAA a(1,2);
AAA &f = GetA(); ---> 이게 왜 실행이 가능한거지?
}
AAA& Get(){
AAA temp(3,4); -----> 이것도 실행가능한데 쓰레기 값이 들어간다.
return temp;
}
-------------------------------------
AAA& ref_AAA(AAA& _a){
return _a;
}
---------->> 일반 변수와는 다르게 클래스는 메인 함수에서 AAA &ref = GetAAA(a); 로 호출해도 문제가 없다. 왜??
AAA GetAAA(AAA & _a){ ---------->> 예를 들어 int형이라면 문제가 생긴다. 상수를 리턴하기 때문. 클래스는 뭐가 다른거지?
return _a;
}
'C++' 카테고리의 다른 글
[C++] 템플릿 // 열혈강의 (0) | 2016.12.12 |
---|---|
[C++] 복사생성자 정리 (0) | 2016.12.07 |
[C++] 연산자 오버로딩 // 열혈강의 (0) | 2016.12.07 |
[C++] virtual 소멸자, virtual table // 열혈강의 (0) | 2016.12.05 |
[C++] 상속에 대하여 // 열혈강의 (0) | 2016.12.01 |