const reference
call by value
- 인자로 전달된 객체의 복사본이 생성된다.
원본 객체를 변경할 수 없기에 안전하지만 복사본에 대한 오버헤드가 있다.
<call by value 에 의해 data 객체를 넘기는 경우>
call by reference with const
void foo (const Data& d)
복사본에 대한 오버헤드를 없애고, 안전하게 값을 사용하게 하기 위해서 const reference를 사용할 수 있다.
또한 복사 생성자와 소멸자가 호출되지 않는다.
#include <iostream>
struct Date
{
int year;
int month;
int day;
};
//void foo(Date d) // call by value
void foo(const Date& d) // const reference : 안전하게 값을 넘겨 사용이 가능하다.
{
// d.year = 1000; // error : const 이기 때문에 값 변경이 불가하다.
}
int main()
{
Date date = {2020, 3, 28};
foo(date);
std::cout << date.year << std::endl; // 2020
}
d.year = 1000; 의 주석을 해제하면 아래와 같은 에러가 발생한다.
main.cpp:13:15: error: assignment of member ‘Date::year’ in read-only object
const reference 가 항상 좋은 것은 아니다.
int 혹은 double 타입 값을 받아 처리하는 함수의 경우는 오히려 const reference 가 안 좋다. 이런 경우 call by value를 사용하면 된다.
- primitive type은 call by value가 좋다.
- user가 정의한 타입의 경우는 const reference가 좋다.
#include <iostream>
void foo(int x) // call by value
//void foo(const int& x)
{
}
int main()
{
int n = 10;
// foo 함수에서는 절대로 n의 값을 변경하면 안된다.
foo(n);
std::cout << n << std::endl; // 반드시 10이 나와야 한다.
}
return by reference
foo()가 호출되면 pt가 return 될 것처럼 보여지지만 사실 리턴용 임시객체가 생성되어 return 된다.
임시 객체는 등호의 왼쪽에 올 수 없기 때문에 아래와 같은 에러가 발생한다.
main() 내부의 foo() 에는 임시 객체가 위치하게 되는 것이다. 그래서 에러 발생!
struct Point
{
int x;
int y;
//Point() {}
};
void f1(Point pt) {} // 복사본 생성
void f2(Point& pt) {} // 복사본 생성 안함.
Point pt = {0,0};
Point foo() // 값 타입반환 return by value
{
return pt;
}
int main()
{
foo().x = 10;
// pt.x => 10
}
main.cpp:22:15: error: using temporary as lvalue [-fpermissive]
아래와 같이 reference 를 사용해 리턴하면 main()에서 foo().x = 10; 수행이 가능해진다.
struct Point
{
int x;
int y;
//Point() {}
};
void f1(Point pt) {} // 복사본 생성
void f2(Point& pt) {} // 복사본 생성 안함.
Point pt = {0,0};
Point& foo() // 리턴용 임시객체를 만들지 않고 pt를 reference로 return 한다.
{
return pt;
}
int main()
{
foo().x = 10;
//pt.x => 10
}
f1()과 같이 함수가 값을 반환하면 :
- 리턴 용 임시객체가 반환된다.
- 등호의 왼쪽에 함수 호출식을 놓을 수 없다. 함수 호출식이 lvalue가 될 수 없다.
#include <iostream>
int x = 10;
int f1() { return x;}
int& f2() { return x;}
int main()
{
f1() = 20; // 10 = 20
std::cout << x << std::endl; // 20
}
f2()와 같이 함수가 참조를 반환하면 :
- 리턴 용 임시객체가 생성되지 않는다.
- 등호의 왼쪽에 함수 호출식을 놓을 수 있다. 함수 호출식이 lvalue가 될 수 있다.
#include <iostream>
int x = 10;
int f1() { return x;}
int& f2() { return x;}
int main()
{
// f1() = 20; // 10 = 20
f2() = 20; // x = 20 ok
std::cout << x << std::endl; // 20
}
* 주의 사항 : reference return 할때, 지역변수를 참조로 반환해서는 안된다!!!
f3() 함수가 int&로 reference 형 함수이기 때문에 f3 함수 안의 n는 지역변수로 절대 return 으로 반환해서는 안된다.
(아래는 잘못된 코드이니 따라하지 말자!)
#include <iostream>
int& f3()
{
int n = 10; // 지역변수 n
return n; // 지역변수는 reference return 으로 반환하면 안된다!!!
}
int main()
{
std::cout << f3() << std::endl;
}
실행해보면 아래와 같이 warning이 뜨는데, 값이 제대로 출력되지 않는 것은 볼 수 있다.
main.cpp:5:9: warning: reference to local variable ‘n’ returned [-Wreturn-local-addr]
revalue reference
int&와 같이 reference타입 변수가 선언되었을 때 등호(=)의 오른쪽에 상수는 올 수 없다.
그런데 int&&와 같은 형태의 reference 타입 변수 선언시에는 등호(=) 오른쪽에 상수만 올 수 있다.
int main()
{
int v1 = 0, v2 = 0;
v1 = 10; // ok 10 : rvalue
10 = v1; // error v1 : lvalue
v2 = v1;
// lvalue reference
int& r1 = v1; // ok
int& r2 = 10; // error
const int& r3 = v1; // ok
const int& r4 = 10; // ok
// rvalue reference : rvalue 만 가리킨다. (C++11부터 지원)
int&& r5 = v1; // error.
int&& r6 = 10; // ok
}
![](https://t1.daumcdn.net/keditor/emoticon/friends1/large/009.gif)
'C++' 카테고리의 다른 글
[C++] 동적메모리 할당 (new, delete), nullptr (0) | 2021.08.15 |
---|---|
[C++] Explicit Casting (명시적 캐스팅) (0) | 2021.08.14 |
[C++] reference 개념 (0) | 2021.08.13 |
[C++] range-for, if init, if constexpr (0) | 2021.08.12 |
[C++] 함수 : Lamda expression (람다 표현식) (0) | 2021.08.11 |
댓글