일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- std::ostream
- std::endl
- delete function
- new&delete
- virtual destructor
- vector size
- suffix return type
- increment operator
- virtual function table
- c++ multi chatting room
- base from member
- std::vector
- 더 지니어스 양면포커
- member function pointer
- C++
- placement new
- c++ basic practice
- constructor
- conversion constructor
- discord bot
- std::cout
- vector capacity
- operator overloading
- pointer to member data
- dynamic_cast
- this call
- diamond inheritance
- virtual function
- return by reference
- virtual inheritance
- Today
- Total
I'm FanJae.
[C++] Reference 본문
※ 본 포스트는 코드누리 C++ Basic 강의 내용을 보고 정리한 포스트입니다.
1. Reference(참조)
1-1. Reference의 정의
#include <iostream>
int main()
{
int n = 10;
int* p = &n;
int& r = n;
r = 20;
std::cout << n << std::endl;
std::cout << &n << std::endl;
std::cout << &r << std::endl;
}
- C 언어에서는 변수의 주소값을 담을 수 있는 Pointer라는 것이 있다.
- C++에서는 포인터와 유사한 형태의 Reference라는 기능이 존재한다. (유사한 것이 결코 같은게 아니다.)
- 포인터 변수를 선언하는 것처럼 다음과 같이 선언이 가능하다.
int &r = n;
- Reference란, 이미 존재하는 변수(메모리)에 대한 추가적인 별칭을 부여하는 문법이다.
- 기존 포인터가 이러한 형태를 띄는 느낌이다. 여기에 r이 추가된 이후, r에 의해 n의 값이 20으로 바뀐 이후 상황을 보자.
※ 즉, 이처럼 r을 이용해서 n에 접근할 수 있다. r과 n은 같은 메모리를 가지는 것을 확인할 수 있다.
- & 연산자는 크게 2가지의 기능이 존재한다.
① 변수의 주소를 구할 때 사용
int n = 0;
int* p = &n;
② 레퍼런스 변수를 선언할 때 사용
int& r = n;
1-2. Reference 와 함수 인자
void inc1(int n) { ++n; }
void inc2(int* p) { ++(*p);}
void inc3(int& r) { ++r; }
int main()
{
int a = 10, b = 10, c = 10;
inc1(a);
inc2(&b);
inc3(c); // 참조 변수의 경우는 주소가 아닌 값을 보내야 한다.
std::cout << a << std::endl;
std::cout << b << std::endl;
std::cout << c << std::endl;
}
- 원래 C 언어 에서는 Call by Reference를 직접 지원하지 않는다.
- 다만, 이를 Pointer를 사용하여, 유사한 형태를 만드는 것이 가능하다.
- C++ 에서는 Refernece가 존재하므로, Call by Reference를 지원한다.
- 참조 변수에 보낼때는 주소가 아닌 원본 값을 그대로 보내주는 것에 유의 해야 한다.
※ 함수 인자로 reference를 사용하면 포인터와 유사하게 전달된 인자의 값을 수정이 가능하다. 그리고, 포인터 보다 간결하고 안전하게 코드 작성이 가능하다.
void f1(int* p)
{
if(p != 0)
{
}
}
void f2(int& r)
{
}
int main()
{
int* p = 0; // 널 포인터는 있다.
int& r; // error. 널 참조는 없다.
// int& r = n;
}
- 이 예제에서, 포인터는 Null 값을 담을 수 있다. 따라서, 함수에서 연산 전에 널 포인터인지 검사를 하는 문장이 필요하다.
- 반면, Reference는 NULL로 초기화 하는것이 불가능하다. 반드시 초기화를 진행해야 한다.
① scanf vs std::cin
- 입력 받을때 C는 scanf를 C++은 std::cin을 사용한다.
- 이들은 모두 사용자가 입력한 값을 인자로 전달한 변수에 담아와야 한다.
scanf("%d", &n); -> 입력한 값을 인자로 전달한 변수에 담아오기 위해 Call by pointer를 사용한다.
std::cin >> n; -> 입력한 값을 인자로 전달한 변수에 담아오기 위해 Call by Reference를 사용한다.
2. Const reference
struct Rect
{
int left;
int top;
int right;
int bottom;
};
void foo ( Rect r )
{
}
int main()
{
Rect rc = {1, 1, 5, 5};
foo(rc);
}
- foo()에 변수 rc를 전달하는데 rc의 상태를 변경하면 안된다고 가정하면, Call by Value로 전달하면 된다.
- 이와 관련해서 Call by value는 다음과 같은 특징이 있다.
① Call by value
- 인자로 전달된 변수를 수정하지 않겠다는 약속이다.
- 구조체 같은 사용자 정의 타입을 인자로 사용하는 경우 복사본에 대한 오버헤드가 존재한다.
※ 위와 같은 문제를 해결해주는 것이 바로 const reference이다.
struct Rect
{
int left;
int top;
int right;
int bottom;
};
//void foo ( Rect r )
void foo (const Rect& r)
{
}
int main()
{
Rect rc = {1, 1, 5, 5};
foo(rc);
}
2-1. const reference ( const Rect & )
- 복사본에 대한 오버헤드 없이 인자로 전달된 변수를 수정하지 않겠다는 약속이다.
- 이는 C++에서 가장 널리 사용되는 인자 전달 방식이다.
struct Rect
{
int left;
int top;
int right;
int bottom;
};
// f1과 f2중 좋은 코드는 무엇인가?
void f1(Rect r) {}
void f2(const Rect& r) {} // 좋은 코드
// f3와 f4중 좋은 코드는 무엇인가?
void f3(int n) {} // 좋은 코드
void f4(const int& r) {}
- 인자의 값을 바꾸지 않는다는 전제하에 f1과 f2 중에는 f2가 더 좋은 코드이다. 복사본에 대한 오버헤드가 없기 때문이다.
- 하지만, f3와 f4 중에는 f3가 더 좋은 코드이다.
- f3,f4중 f3가 더 좋은 코드인 이유는 int와 같은 primitive type은 타입의 크기가 크지 않고, Reference를 사용하는 것 보다 더 많은 컴파일러 최적화가 지원된다.
2-2. 함수 인자를 받는 방법
① 인자의 값을 변경하는 경우
- Pointer, Reference 모두 가능.
- C++에서는 레퍼런스를 좀 더 많이 사용한다.
pointer : void swap(int* p1, int* p2)
reference : void swap(int& r1, int& r2)
② 인자의 값을 변경하지 않는 경우
- Pointer, Reference 모두 가능.
- C++에서는 레퍼런스를 좀 더 많이 사용한다.
User define type | const refernece 사용. 일반적으로 타입의 크기가 크다 메모리 사용량 증가, 복사 생성자 호출의 오버헤드를 줄이기 위해 사용한다. |
Primitive type | call by value 사용. 타입의 크기가 크지 않고, 생성자 개념이 없고, Reference를 사용하는 것보다 더 많은 컴파일러 최적화가 지원 된다. |
'C++ > Basic' 카테고리의 다른 글
[C++] Explicit casting (0) | 2024.08.11 |
---|---|
[C++] nullptr (0) | 2024.08.11 |
[C++] 연산자와 제어문 (0) | 2024.08.09 |
[C++] Function III (0) | 2024.08.08 |
[C++] Function III (0) | 2024.08.08 |