포인터도 힘들었는데...참조자라니
아직도 기억이 생생하다...
포인터를 이해하기 위해 고생을 했고 사실 아직도 헷갈린다는걸,,,
근데 왜 C++에는 참조자까지 있는거냐고,,울고싶어라
그래서 참조자가 뭔데
결론부터 말하자면, 변수의 또 다른 이름(별명)을 컴파일러에게 알려주는 것이다!
참조자를 정의하는 법은 가리키고자 하는 타입 뒤에 &를 붙여주면 된다
주의할점은 참조자는 반드시 선언과 정의를 동시에 해줘야 한다.
또한, 참조자는 한번 어떤 변수의 참조자가 되어버리면, 더 이상 다른 변수를 참조할 수 없게 된다.
예시를 보도록 하자
#include <iostream>
int main(void)
{
int a = 2;
int &ref_a = a;
std::cout << "a : " << a << std::endl;
std::cout << "ref_a : " << ref_a << std::endl;
a = 3;
std::cout << "a : " << a << std::endl;
std::cout << "ref_a : " << ref_a << std::endl;
ref_a = 4;
std::cout << "a : " << a << std::endl;
std::cout << "ref_a : " << ref_a << std::endl;
return (0);
}
C++
복사
결과
위에서 확인할 수 있듯이, 새로운 이름이기 때문에 a에서 바꾸든 ref_a에서 바꾸든 모두가 바뀌는 것을 확인할 수 있다.
참조자의 특이한 특성으로는, 포인터와는 달리 메모리상에 존재하지 않을 수도 있다.
컴파일러에게 새로운 별명을 알려주는 것이기 때문에 결국 똑같은 주소를 가지고 있다고 생각하면 편하다
여기서 주의할점은, 항상 메모리 상에 존재하지 않는 것은 아니다.
위의 그림처럼 메모리의 스택 영역은 함수의 호출과 관계되는 지역 변수와 매개변수가 저장되는 영역이다. 따라서, 함수 인자를 참조자로 전달받게 되면, 메모리가 할당되게 된다.
포인터랑 다를게 없는 거 같은데 굳이 왜 쓰는거야
1.
한번 초기화되면 절대 다른 객체를 참조할 수 없으므로 포인터보다 안전하다
처음에 설명했듯 참조자는 한번 어떤 변수의 참조자가 되어버리면, 더 이상 다른 변수를 참조할 수 없게 된다. 따라서 포인터보다 안전하다
위의 사진처럼, ref_a = b 를 하게 되면 새롭게 참조를 하는 것이 아니라 b의 값이 ref_a에 대입이 되는 것을 확인할 수 있다.
2.
코드가 깔끔해진다
우리가 포인터를 처음 배울때 많이 연습한 swap함수를 보자
#include <iostream>
void swap(int* a, int* b)
{
int temp = *a;
*a = *b;
*b = temp;
}
int main()
{
int a = 10;
int b = 20;
std::cout << "Before Swap" << std::endl;
std::cout << a << std::endl;
std::cout << b << std::endl;
swap(&a, &b);
std::cout << "After Swap" << std::endl;
std::cout << a << std::endl;
std::cout << b << std::endl;
return (0);
}
C++
복사
간단한 코드라서 덜하지만 *와 &가 여기저기서 날 괴롭게 한다. 하지만 참조자를 쓰게 되면 다음과 같이 바뀌게 된다.
#include <iostream>
void swap(int& a, int& b)
{
int temp = a;
a = b;
b = temp;
}
int main()
{
int a = 10;
int b = 20;
std::cout << "Before Swap" << std::endl;
std::cout << a << std::endl;
std::cout << b << std::endl;
swap(a, b);
std::cout << "After Swap" << std::endl;
std::cout << a << std::endl;
std::cout << b << std::endl;
return (0);
}
C++
복사
그렇지만, 포인터만을 사용해야 하는 경우도 있다.
참조자는 선언과 동시에 초기화가 되어야 하기 때문에 NULL이 허용되지 않는다. 따라서 매개변수에 NULL 포인터를 넘겨주거나 리턴값으로 NULL 포인터를 반환해야 할 경우 포인터를 사용해야 한다.
피드백은 언제나 환영입니다! 잘 부탁드리겠습니다