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;


}

+ Recent posts