출처: https://www.geeksforgeeks.org/passing-by-pointer-vs-passing-by-reference-in-c/
Pass-by-Value와 Pass-by-pointer / Reference 를 쉽게 구분하려면
호출된 함수에서 값 변경이 호출한 함수에 영향을 미치는가의 유무로 나눌 수 있다.
그러다 든 의문은 Pass-by-Pointer 와 Pass-by-Referecne의 차이점과 써야하는 상황(?)이였다.
먼저 포인터와 레퍼런스의 차이점을 간략히 비교한 뒤
Pass-by-Pointer 와 Pass-by-Referecne 의 차이점을 알아본다.
Reference 는 말 그대로 같은 Object에 다른 이름을 붙인 것이다. 따라서 포인터처럼 NULL 값이 올 수 없어서 더 안전하다.
포인터는 다른 값으로 재 할당이 가능하다. 하지만 레퍼런스는 선언과 동시에 별명을 붙여주고 그 이후 레퍼런스가 가르키는 객체에 대한 변경이 불가능하다.( a의 레퍼런스 C를 코드상에서 b의 레퍼런스로 변경하는 것이 불가능하다는 얘기이다)
포인터는 NULL값을 할당받을 수 있다. 레퍼런스는 불가하다.
포인터는 증감연산을 통해 가르키는 배열을 iterate 할 수 있다. 레퍼런스는 배열을 가르킨다면 index 방식으로 iterate 해야한다.
포인터는 메모리를 가르키는 변수이다. 근데 메모리상에서 포인터도 존재해야하므로 메모리 0X100번주소에 할당된 포인터의 변수 값이 0X200번주소인 식이다. 레퍼런스는 추종하는 객체와 동일한 메모리 주소를 가진다. /
클래스나 구조체에서 멤버에 접근할때 포인터는 -> (Arrow Operator) 를 쓰지만 레퍼런스는 . (Dot Operator) 을 쓴다.
포인터가 가르키는 값은 *로 Deference 된다. 레퍼런스는 그냥 쓰면 된다.
Parameter passing 에서 레퍼런스가 선호된다. 하지만 이는 "재할당"이 필요하지 않을 때 얘기이다. 전반적으로 할 수 있으면 레퍼런스텍스트를 쓰고 포인터를 꼭 써야만 하는 상황에는 포인터를 쓰라고 할 수 있겠다.
출처: 씹어먹는 C++ 강의<2. C++ 참조자(레퍼런스)의 도입>
기본적으로 함수에 파라미터를 전달할때 복사가 일어난다.
int function(){
int a = 2;
return a;
}
int main(){
int b = function();
return 0;
}
변수 a의 값 2를 b에 복사 하여 할당함.
function 함수가 종료되면 a는 메모리에서 소멸된다.
int& function() {
int a = 2;
return a;
}
int main() {
int b = function();
b = 3;
return 0;
}
변수 a의 레퍼런스를 b에 복사하여 할당함.
function 함수가 종료되면 a는 메모리에서 소멸된다.
그럼 a의 레퍼런스도 없어질 것이다. 그럼 b는?
Undefined Behavior이다. Dangling reference
int& function(int& a) {
a = 5;
return a;
}
int main() {
int b = 2;
int c = function(b);
return 0;
}
c에다 b의 값을 대입하는거랑 동일하다.
int function() {
int a = 5;
return a;
}
int main() {
int& c = function();
return 0;
}
이또한 Dangling reference 이다.
하지만 예외가 하나 존재한다.
int function() {
int a = 5;
return a;
}
int main() {
const int& c = function();
std::cout << "c : " << c << std::endl;
return 0;
}
const int& 처럼 const reference로 받으면 a의 생명이 레퍼런스가 소멸될 때 까지 연장된다.
정리
| 함수에서 값 리턴 ( int f() ) | 함수에서 레퍼런스 리턴 ( int& f() ) | |
|---|---|---|
| 값 타입으로 받는경우 (int a = f()) | a 로 값이 복사된다 | a 로 값이 복사된다 다만 지역변수의 레퍼런스를 리턴하지(중간에 소멸되는거) 않도록 주의 Dangling reference |
| reference 타입으로 받는 경우 (int& a = f()) | 컴파일 오류 ( 간혹 안나는 경우도 있는데 Undefined Behavior 이다. 심각한 버그를 초래할 수 있음) | 가능하다 다만 지역변수의 레퍼런스를 리턴하지(중간에 소멸되는거) 않도록 주의 Dangling reference |
| const reference 타입으로 받는 경우 (const int& a = f()) | 가능 | 가능. 다만 마찬가지로 지역 변수의 레퍼런스를 리턴하지 않도록 주의 |