반응형
Notice
Recent Posts
Recent Comments
Link
Brise
[C++ 기본 2] 1. reference 본문
반응형
C에서 C++로 넘어오게 되면서 큰 차이를 느끼는 문법 중의 하나가 바로 reference의 존재이다.
reference의 경우 변수에 대한 별명을 부여하여 사용은 변수처럼, 동작은 포인터처럼 동작 가능한 C++에서 추가된 변수 타입이다.
물론 이를 통하여 편리함을 얻게 되었지만, 문법을 잘 아는 것이 아니라면 call by value인지 call by reference인지 헷갈리는 경우가 있다.
// 1_레퍼런스.cpp 41 page
#include <iostream>
// 핵심 1. 기존 변수(메모리)에 새로운 이름을 부여 하는 것
// 2. 레퍼런스 변수 선언시 반드시 초기값이 있어야 합니다.
int main()
{
int n1 = 10;
int n2 = n1;
int* p1 = &n1;
int& r1 = n1; // C++ 에서 추가한 새로운 타입
r1 = 30;
std::cout << n1 << std::endl; // 30
// 결국 r1의 주소와 n1의 주소는 동일 합니다.
std::cout << &r1 << std::endl;
std::cout << &n1 << std::endl;
// 포인터와 레퍼런스는 모두 기존 메모리를 가리킬수 있습니다.
// null 포인터는 존재 할수 있지만 null 레퍼런스는 존재 할수
// 없습니다
int& r2; // error
int* p2 = nullptr; // ok
}
// 1_레퍼런스2
#include <iostream>
// 43 page
// 포인터와 레퍼런스의 용도는 유사합니다.
// 1. "자동 dereference 되는 포인터" 가 레퍼런스 입니다
// 2. 포인터는 if ( p != nullptr ) 이 필요 하지만
// 레퍼런스는 필요 없습니다. - 포인터 보다 안전.
// C++ 에서는 포인터 보다 레퍼런스를 더 많이 사용합니다.
void inc1(int n) { ++n; }
void inc2(int* p) { ++(*p); }
void inc3(int& r) { ++r; }
int main()
{
int a = 1, b = 1, c = 1;
inc1(a); // call by value. 원본 수정 안됨
inc2(&b); // call by pointer. 원본 수정 가능
inc3(c); // call by reference. 원본 수정 가능
std::cout << a << std::endl;
std::cout << b << std::endl;
std::cout << c << std::endl;
// 사용자 입력을 받아 올때
scanf("%d", &a); // 2번째 인자가 포인터 입니다.
cin >> a; // >> 함수의 인자가 참조 입니다.
}
위의 설명과 같이 reference 타입은 "자동으로 dereference 되는 포인터" 이다 때문에 dereference 되지 않는 특성(i.e. nullptr)이 존재하지 않도록 컴파일러가 막게 된다.
// 1_레퍼런스3. 45 page
struct BigData
{
int buff[1024];
};
// call by value 의 특징 : 값을 수정하지 않겠다는 의도.
// 하지만, 복사본이 생성되므로
// 메모리 부담이 크다.
//void foo(BigData n)
// 핵심 : call by value 대신 const &가 좋다.!
void foo(const BigData& n)
{
//n.buff[0] = 10; // error. n은 상수
}
int main()
{
//int x = 100;
BigData x;
// 어떤 함수에서 인자의 값을 절대 수정하면 안된다면
foo(x);
}
// C++에서 함수 인자 만들기
// 1. 인자의 값을 변경하고 싶을때 - 포인터 또는 레퍼런스
void foo(int* p) {}
void foo(int& r) {}
// 2. 인자의 값을 변경하지 않을때
// A. 인자가 user type 일때 - 일반적으로 크기가 작지 않으므로
// call by value 보다는 const 참조가 좋다
void foo(const UserType& t) {}
// B. 인자가 primitive type 일때
void foo(int t) {}
함수의 인자로 대형의 데이터를 전달할 때 값을 변경하지 않기를 원하는 경우 const referencetype을 사용할 수 있다.
// 1_레퍼런스4. 100 page
// 핵심 : 함수가 참조를 반환하면 등호에 왼쪽에 놓을수 있습니다.
int x = 0;
int foo() { return x; } // 값 타입 반환 : 메모리에 있는 값 반환
int& goo() { return x; } // 참조 반환 : 값이 아닌 메모리 반환
// 주의 : 절대 지역변수를 참조 반환 하면 안됩니다.
int& hoo()
{
int n = 0;
return n;
}
int main()
{
int n1 = 0, n2 = 0;
n2 = n1; // n1이 오른쪽에 있다. 컴파일러는 n1의 값을
// 가져오는 코드 생성
n1 = 10; // n1이 왼쪽에 있다. 컴파일러는 n1의 주소를
// 사용하는 코드 생성
foo() = 20; // error
goo() = 20; // ok..
}
// google 에서 C++ core guideline
// 2번째 링크
자동 dereference 되는 특성을 가지고 있기 때문에 등호의 왼쪽에도 reference 타입이 쓰일 수 있다.
본래 *ptr = data; 에서 레퍼런스 타입은 자동으로 디레퍼런싱을 수행하기 때문에
ref_func() = data; 와 같은 동작이 성립한다.
반응형
'프로그램 > C,C++' 카테고리의 다른 글
[C++ 기본 2] 4. OOP(Object Oriented Programming) (0) | 2022.02.23 |
---|---|
[C++ 기본 2] 3. example(reference, template) (0) | 2022.01.29 |
[C++ 기본 2] 2. memory allocation (0) | 2022.01.29 |
[C++ 기본] 11. nullptr (0) | 2022.01.29 |
[C++ 기본] 10. Casting (0) | 2022.01.29 |
[C++ 기본] 9. 제어문 (0) | 2022.01.29 |
[C++ 기본] 8. 반복문 (0) | 2022.01.29 |
Comments