----------------
title : C++ 레퍼런스 - std::move 함수
cat_title :  move
ref_title : move, std::move
path : /C++ Reference/utility
publish_date : 2019-09-26
----------------

##@ cpp-ref-start

#@ std::move

`<utility>` 에 정의됨

```cpp-formatted
// C++ 14 이전에는 constexpr 아님!
template <class T>
constexpr typename std::remove_reference<T>::type&& move(T&& t) noexcept;
```

`std::move` 는 어떤 객체 `t` 가 **이동 될 수 있음** 을 알려준다. **이동** 이라 하면 `C++ 11` 에 도입된 개념으로 `t` 가 가지고 있는 자원을 다른 객체에게 효율적으로 전달하는 것을 의미한다. **다시 한 번 말하지만 `std::move` 는 이동을 수행하지 않는다. 이동 될 수 있음을 알려줄 뿐이다.**

엄밀히 말하자면, `std::move` 는 객체 `t` 를 나타내는 \serif{xvalue} 식을 만들어준다 ([xvalue 가 뭔지, lvalue, rvalue 때문에 머리가 아프신 분들은 값 카테고리에 관한 이 글을 참조 바람](/294)) 쉽게 말해 그냥 `t` 를 우측값 레퍼런스 타입으로 `static_cast` 하는 것과 동일하다.

`std::move` 된 객체를 함수에 전달한다면, 우측값 레퍼런스를 인자로 받는 함수(예를 들어서 이동 생성자, 이동 대입 연산자, `vector` 의 `push_back` 함수 같은 애들)가 오버로딩 되어서 선택된다. 참고로 우측값 레퍼런스 자체는 \serif{rvalue} 가 아니라 \serif{lvalue} 이기 때문에, 이동 생성자나 이동 대입 연산자 내부에서 `std::move` 를 호출하는 경우가 많다. (아래 예시 참조)

```cpp-formatted
// 이동 생성자
A(A&& arg)
    : member(
        std::move(arg.member))  // "arg.member" 식 자체는 좌측값 (lvalue) 이다.
{}
// 이동 대입 연산자
A& operator=(A&& other) {
  member = std::move(other.member);
  return *this;
}
```

유일한 예외적인 상황은 함수 인자가 템플릿 인자의 우측값 레퍼런스인 경우 이다 (이를 보통 *Universal reference* 라고 한다). 이 경우 `std::forward` 를 사용해야 한다.

한 가지 주의할 점으로 이미 이동되서 껍데기만 남은 객체를 접근하면 안된다. 예를 들어서

```cpp-formatted
std::vector<std::string> v;
std::string str = "example";
v.push_back(std::move(str));  // str 은 이제 껍데기만 남음
str.back();                   // 정의되지 않은 작업!
str.clear();                  // 다만 clear 자체는 가능하다.
```

### 인자들

* t	: 이동 시키고 싶은 객체

### 리턴값

`static_cast<typename std::remove_reference<T>::type&&>(t)`

### 실행 예제

```cpp-formatted
#include <iostream>
#include <string>
#include <utility>
#include <vector>

int main() {
  std::string str = "Hello";
  std::vector<std::string> v;

  // push_back(const T&) 가 오버로딩 되어서 문자열의 복사가 발생한다.
  v.push_back(str);
  std::cout << "After copy, str is \"" << str << "\"\n";

  // push_back(T&&) 가 오버로딩 되서 문자열의 복사 없이 그대로 전달된다.
  v.push_back(std::move(str));

  // 일반적으로 이동된 객체를 접근하는 것은 안되지만 C++ string 의 경우
  // 비어있음이 보장된다.
  std::cout << "After move, str is \"" << str << "\"\n";

  std::cout << "The contents of the vector are \"" << v[0] << "\", \"" << v[1]
            << "\"\n";
}
```

```exec
After copy, str is "Hello"
After move, str is ""
The contents of the vector are "Hello", "Hello"
```

### 참고 자료

* `forward` : 함수의 인자를 전달한다.
* `move_if_noexcept` : 생성자가 예외를 던지지 않을 경우에만 우측값 레퍼런스를 얻는다.