모두의 코드
C++ 레퍼런스 - std::move 함수
std::move
<utility> 에 정의됨
// 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
를 나타내는 xvalue 식을 만들어준다 (xvalue 가 뭔지, lvalue, rvalue 때문에 머리가 아프신 분들은 값 카테고리에 관한 이 글을 참조 바람) 쉽게 말해 그냥 t
를 우측값 레퍼런스 타입으로 static_cast
하는 것과 동일하다.
std::move 된 객체를 함수에 전달한다면, 우측값 레퍼런스를 인자로 받는 함수(예를 들어서 이동 생성자, 이동 대입 연산자, vector
의 push_back 함수 같은 애들)가 오버로딩 되어서 선택된다. 참고로 우측값 레퍼런스 자체는 rvalue 가 아니라 lvalue 이기 때문에, 이동 생성자나 이동 대입 연산자 내부에서 std::move 를 호출하는 경우가 많다. (아래 예시 참조)
// 이동 생성자 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 를 사용해야 한다.
한 가지 주의할 점으로 이미 이동되서 껍데기만 남은 객체를 접근하면 안된다. 예를 들어서
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)
실행 예제
#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"; }
실행 결과
After copy, str is "Hello" After move, str is "" The contents of the vector are "Hello", "Hello"
참고 자료
forward : 함수의 인자를 전달한다.
move_if_noexcept
: 생성자가 예외를 던지지 않을 경우에만 우측값 레퍼런스를 얻는다.
댓글을 불러오는 중입니다..