1. reference
#include <iostream>
int main() {
int n = 10;
n = 20;
int& r = n; // 레퍼런스
r = 30; // n = 30. n에 30을 넣은것과 같음
std::cout << n << std::endl;
std::cout << r << std::endl; // 같음
std::cout << &n << std::endl;
std::cout << &r << std::endl; // 같음
}
- 변수
=> 메모리의 특정 위치를 가르키는 이름
=> 코드안에서 해당 메모리에 접근하기 위해 사용
- 레퍼런스 변수
=> 기존 변수(메모리)에 또 다른 이름(alias)를 부여하는 것
1.1 함수 인자 전달 방식
#include <iostream>
void f1(int n) { ++n; }
void f2(int* p) { ++(*p); }
void f3(int& r) { ++r; }
int main() {
int a = 0, b = 0, c = 0;
f1(a);
f2(&b);
f3(c);
std::cout << a << std::endl;
std::cout << b << std::endl;
std::cout << c << std::endl;
int* p = &n;
int& r = n;
}
- int a = 0, b = 0, c = 0; 에서 초기화 했을 때의 메모리
- f1(a)의 실행 과정
=> f1함수에서 int n을 새로운 메모리에 할당(n)
=> 새로운 메모리에 선언된 변수의 값이 증가
=> C에서의 call by value / 원본을 수정할 수 없다.
=> 실행결과는 0
- f2(&b)의 실행 과정
=> 포인터 변수가 만들어지며, 2000이라는 주소를 받게 됨
=> 또 다른 메모리를 잡긴 했지만 주소를 갖고 있고, 2000번지를 따라가서 값이 증가되어 b가 1증가됨
=> C에서의 call by reference / 원본을 수정할 수 있다.
=> 실행결과는 1
- f3(c)의 실행 과정
=> C++의 reference / 원본을 수정할 수 있다.
1.2 포인터(Pointer)와 레퍼런스(Reference)
#include <iostrea>
int main() {
int n = 10;
int* p1 = &n;
int& r1 = n;
int* p1;
int& r2 = 0;
*p1 = 20;
r1 = 20;
if(p1 != 0) {}
//if(r1 != 0) {}
}
- 유사한 점
=> 기존 변수(메모리)를 가리킨다.
- 차이점
2. const reference
#include <iostream>
struct Date {
int year;
int month;
int day;
};
void move(Date d) { // call by value
d.year = 1000; // 값이 변하지 않는다.
}
int main() {
Date date = {2019, 10, 22};
move(date);
std::cout << date.year << std::endl;
}
2.1 call by value의 특징
=> 인자로 전달된 객체의 복사본이 생성된다.
=> 원본 객체를 변경할 수 없다. - 안전하다.
=> 하지만, 복사본에 대한 오버헤드가 있다.
2.2 인자의 값을 변경하지 못하는 함수를 만들려면
// void move(Date d)
void move(Date& d) {
d.year = 1000;
}
=> 레퍼런스로 바꿔준다.
=> 하지만 레퍼런스로 받음으로써 원본의 값이 변경될 수 있다.
void move(const Date& d) {
// d.year = 1000; - error
}
=> 이 때, const를 붙여주면 원본의 값을 바꿀 수 없게 된다.
=> 여기서는 값을 변경하기 위해 레퍼런스를 쓰는게 아닌, 값을 못 바꾸게 하기 위해 레퍼런스를 사용했다.
2.3 const reference의 장점
=> 인자에 대한 복사본을 만들지 않는다.
=> 복사 생성자와 소멸자가 호출되지 않는다.
2.4 함수 인자 전달 방법 정리
#include <iostrea>
void move(? x) {
}
int main() {
int n = 10;
// move 함수에서는 절대로 n의 값을 변경하면 안된다.
move(n);
std::cout << n << std::endl; // 반드시 10이 나와야 한다.
}
- 조건 : n의 값을 절대 변경하면 안된다. 위의 move함수의 인자타입은 어떻게 들어가야 할까?
- move(int x) - call by reference | move(const int& x) - const reference
- 위에선 복사본이 만들어지기 때문에 const reference가 좋다고 했지만, int타입은 메모리의 용량이 크지도 않고, 이러한 표준 타입은 call by value가 참조로 받았을 때보다 최적화가 훨씬 잘 되어 있다.
- 또한 참조로 받았을 때, 상황에 따라 메모리가 정말 안잡히는게 아닌 내부적인 원리로 어떤 포인터가 잡힐 수 있다.
- 따라서 이러한 int or double타입(표준 타입)일 경우 call by value가 더 낫다.
1. 함수 안에서 인자의 값을 변경하고 싶다면
=> 포인터 또는 참조를 사용해서 전달 받는다.
2. 함수 안에서 인자의 값을 변경하지 못하게 하려면
- primitive type => call by value가 좋다.
- user define type => const reference가 좋다.
3. reference return
struce Point {
int x;
int y;
};
void t1(Point pt) {} // 복사본 생성
void t2(Point& pt) {} // 복사본 생성 안함
3.1 함수 인자
- call by value => 복사본을 생성한다.
- call by reference => 복사본을 생성하지 않는다.
struce Point {
int x;
int y;
};
Point pt = {0, 0};
Point pm() { // 값 타입 반환 return by value
retrun pt;
}
int main() {
pm().x = 10; // error
}
3.2 함수 반환값
- main함수내의 pm()함수는 pt를 반환한다. 그럼 pm()자리에 pt가 오게 되는데 이 pt가 원본일까?
- 값타입을 반환했기 때문에 리턴 용 임시 객체가 생성되어 반환된다.
- 특히 리턴 용 임시 객체는 C++에서 등호의 왼쪽에 올 수 없게 되어 main함수 내의 문법은 에러가 난다.
struce Point {
int x;
int y;
};
Point pt = {0, 0};
// Point pm() { // 값 타입 반환 return by value
Point& pm() {
retrun pt;
}
int main() {
pm().x = 10; // ok
}
3.3 reference 와 함수 반환값
#include <iostream>
int x = 10;
int t1() { return x; } // 값
int& t2() { return x; } // 참조
int main() {
t1() = 20; // 10 = 20 - error
t2() = 20; // x = 20 - ok
}
* 주의! => 절대, 지역변수를 참조로 반환하면 안된다.
4. rvalue reference
int main() {
int v1 = 0, v2 = 0;
v1 = 10; // ok
10 = v1; // error
v2 = v1;
// lvalue reference
int& r1 = v1; // ok
int& r2 = 10; // error
// const lvalue reference
const int& r3 = v1; // ok
const int& r4 = 10; // ok
// rvalue reference : rvalue만 가르킨다.
int&& r5 = v1; // error
int&& r6 = 10; // ok
}
4.1 lvalue와 rvalue
4.2 reference 규칙
4.3 rvalue reference가 사용되는 분야
=> move semantics
=> perfect forwarding
'프로그래밍 > C++' 카테고리의 다른 글
[C++] 동적 메모리 할당, nullptr (0) | 2019.10.27 |
---|---|
[C++] Explicit Casting (0) | 2019.10.25 |
[C++] range for / if init / if constexpr (0) | 2019.10.18 |
[C++] C언어와 다른 C++ 함수(2) (0) | 2019.10.11 |
[C++] C언어와 다른 C++ 함수(1) (0) | 2019.10.09 |