C++ 아이콘 제작자: Darius Dan - Flaticon
- 함수에 객체를 전달해 함수 내부에서 새로운 객체에 복사를 하고 그 새로운 객체를 리턴하는 함수
ㄴ임시객체로 하여금 여러번 복사가 일어나는 경우가 많다.
ex) 어떤 같은 타입의 객체끼리 대입, 그리고 함수 호출 등에서 너무 빈번하게 복사가 일어남
==> 매번 복사를 하는 오버헤드를 처리하고 싶어
( 만약 큰 자원을 사용한다면 레퍼런스로 주소만을 전달해 간단하고 적은 오버헤드로 처리)임시객체는 해당 범위를 벗어나면 사라진다.
==> 근데 사라지는 것을 사용하고 싶어 ( 레퍼런스를 전달하니 객체를 계속 사용가능 )
==> 그래서 임시객체에 대해서 복사 생성자가 아닌 따로 특별하게 처리하는 이동 생성자를 만듦
임시객체 리턴을 복사해서 새로운 객체 만드는게 아니라
임시객체의 데이터들의 주소들을 넘긴다.
간단하게 기존의 데이터를 새로운 객체 내용을 얕은 복사를 수행한다
(동적할당한 변수는 그냥 그대로 가리키고 일반 변수는 그냥 복사)
그럼 같은 데이터를 2개의 객체에서 가리키니 기존 객체는 nullptr를 가리켜 임시객체가 소멸되도 메모리 해제를 못하게 막는다. (이렇게 임시객체 내용을 사라지지 않고 계속 유지 가능)
대입 할 때 자기 자신을 자기에 대입할 때는 그냥 *this를 리턴
아니라면 위 처럼 내용을 이동시킨다. (기본적인 대입 연산자와 같다)
중요한건 새로운 데이터를 가리키는 것이니 (기존 객체의 입장에선) 기존 데이터 메모리를 해제해줘야 한다.
rvalue 레퍼런스를 전달 받아 함수 내에서 사용을 하는데 함수 내에서는 해당 변수 표현식이 lvalue가 된다.
함수 내에서는 이름을 가지기 때문이다, 실제로 lvalue로써 활용을 한다.rvalue레퍼런스를 다른 곳으로 연속으로 전달을 할 때 해당 rvalue의 성질이 계속 있어야한다
==> 완벽한 전달로 해결한다.
위에서 말한 함수 내부에서 lvalue로써 작동하기 생기는 문제니 그것을 rvalue로 만들면 된다.
==> std::move()를 사용하여 바꿀 수 있다.
일반적으로 T&& 에는 rvalue만 들어가고, T&에는 lvalue만 들어간다.
하지만 템플릿에서는 상황이 달라진다
rvalue 레퍼런스(T&&)을 받는 템플릿 함수가 있다면 ravlue는 당연하고 lvalue까지 받아서 인스턴스화한다. ==> 이것을 universal reference라고 한다. (보편 참조)
- 여기서 해당 템플릿으로 2개의 값이 다 작동하는데 rvalue의 경우 내부에서 lvalue로 바뀌니
move를 사용할 것이다.- 근데 진짜 lvalue도 들어올 수 있으니 만약 들어온다면 move로 인해 반대로 lvalue가 rvalue로 바뀐다. (ref함수도 마찬가지)
==> forward함수로 해결한다.
template <class S>
S&& forward(typename std::remove_reference<S>::type& a) noexcept {
return static_cast<S&&>(a);
}
s가 A& 라면
A&&& forward(typename std::remove_reference<A&>::type& a) noexcept { return static_cast<A&&&>(a); }가 되어서 레퍼런스 겹침 규칙에 따라
A& forward(A& a) noexcept { return static_cast<A&>(a);}가 된다.
template<class T>
void Test(T&& t) {
std::forward<T>(t);
}
사용을 할 때 꼭
<T>으로 템플릿 파라미터를 명시해줘야 rvalue 받는 코드는 위와 같이 작동한다.
typedef int& T;
T& r1; // int& &; r1 은 int&
T&& r2; // int & &&; r2 는 int&typedef int&& U;
U& r3; // int && &; r3 는 int&
U&& r4; // int && &&; r4 는 int&& ==> 이 친구만 &&로 표현됨
개인 공부 기록용 블로그입니다.
틀린 부분 있으다면 지적해주시면 감사하겠습니다!!