티스토리 뷰
[Effective Modern C++] 항목 23. std::move와 std::forward를 숙지하라
pppgod 2019. 11. 23. 13:25C++11 에 등장한 move semantic 에 중요한 함수 두가지가 있다. 바로 std::move 와 std::forward 함수이다. std::forward 는 std::move 함수를 이해하면 쉽게 이해할 수 있으므로 먼저 std::move 에 대해서 알아보자.
std::move
함수의 이름만 보면 std::move 가 이동을 수행해줄 것처럼 보이지만 사실 타입 캐스팅이 전부이다. 그런데도 이 함수의 이름이 move 인 이유는 오른값으로 캐스팅을 하기 때문이다. std::move 를 구현하면 다음과 같이 구현할 수 있다.
template<typename T>
decltype(auto) move(T&& param)
{
using ReturnType = remove_reference_t<T>&&;
return static_cast<ReturnType>(param);
}
move 함수가 캐스팅만 해주다보니 std::move 함수를 사용하더라도 이동이 되지 않는 경우가 있다.
class Annotation {
public:
explicit Annotation(const std::string text)
: value(std::move(text))
{ ... }
...
private:
std::string value;
};
위의 코드에서 text 를 value 로 이동시키려고 했지만 실제로는 복사가 된다. 그 이유는 const 때문이다.
class string {
public:
...
string(const string& rhs);
string(string&& rhs);
...
};
std::move(text) 의 결과는 const std::string 형식의 오른값이다. 이 값은 이동 생성자에 전달이 불가능하다. 그 이유는 이동 생성자에는 const 타입이 아니기 때문이다. 그러나 복사 생성자에는 전달이 가능하다. const 에 대한 왼값 참조를 const 오른값에 묶는 것이 허용되기 때문이다. 따라서 복사생성자가 호출되게 된다. 여기서 얻게되는 한가지 교훈은 이동을 지원할 객체는 const 로 선언하지 말아야하는 것이다. 우리가 알지 못하게 복사 연산으로 변환될 수 있다.
std::forward
std::forward 와 std::move 는 거의 같은 역할을 한다. 차이가 있다면 std::forward 는 조건부 캐스팅을 한다는 것이다. 보편 참조를 하는 경우에 이 값이 우측값인지 좌측값인지 우리는 알지 못한다. 코드를 통해 살펴보자.
void process(const Widget& lvalArg);
void process(Widget&& rvalArg);
template<typename T>
void logAndProcess(T&& param) // 보편참조
{
auto now = std::chrono::system_clock::now();
makeLogEntry("Calling 'process'", now);
process(std::forward<T>(param));
}
Widget w;
logAndProcess(w);
logAndProcess(std::move(w));
logAndProcess 함수에 전달하는 인자를 좌측값과 우측값으로 보내는 경우로 나누어보았다. param 의 타입 또한 인자가 좌측값이냐 우측값이냐에 따라 좌측값이 될수도 우측값이 될수도 있다. 여기서 좌측값으로 전달되었다고 가정해보자. param 의 타입 또한 좌측값이 될 것이며 const Widget& 을 사용하는 process 함수가 호출 될 것이다. 그런데 만약 std::forward 가 아닌 std:;move를 사용했다면 Widget&& 을 사용하는 process 함수가 호출 될 것이다. 이는 어떤 결과를 만들어낼지 아무도 예측하지 못한다. 이처럼 보편참조를 사용하는 경우에는 std::forward 를 사용해야 안전하다.
참고 서적
스콧 마이어스, Effective Modern C++
'C++ > Effective Modern C++' 카테고리의 다른 글
- Total
- Today
- Yesterday
- Perfect
- thread
- detach
- async
- Forwarding
- CPP
- forward
- C
- Join
- std::move
- auto
- 다이소
- const
- Effective
- Overloading
- Modern
- Effective Modern C++
- 보편 참조
- 람다
- Unreal
- std::forward
- C++
- C++11
- Override
- Future
- 발아시기
- C++14
- 보편참조
- 포인터
- MOVE
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 | 31 |