utility_move

utility_move (이동 의미론)

std::move는 C++11부터 제공되는 유틸리티 함수로, 객체를 "이동 가능한 상태"로 만들어 주는 캐스팅 도구예요. 이 함수를 사용하면 객체의 리소스를 다른 객체로 효율적으로 전달할 수 있어요. 주로 이동 생성자나 이동 대입 연산자에서 활용된답니다.

출처: cppreference

본문

Defined in header
template < class T > typename std :: remove_reference < T >:: type && move ( T && t ) noexcept ; (since C++11) (until C++14)
template < class T > constexpr std :: remove_reference_t < T >&& move ( T && t ) noexcept ; (since C++14)

std::move는 객체 t가 "이동될 수 있음"을 나타내는 데 사용돼요. 즉, t의 리소스를 다른 객체로 효율적으로 전송하는 것을 허용하는 거예요.

특히, std::move는 인자 t를 식별하는 xvalue 표현식을 생성해요. 이는 rvalue 참조 타입으로의 static_cast와 정확히 동일해요.

매개변수 (Parameters)

t - 이동할 객체

반환값 (Return value)

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

참고 사항 (Notes)

rvalue 참조 매개변수를 받는 함수들(이동 생성자, 이동 대입 연산자, std::vector::push_back 같은 일반 멤버 함수 포함)은 rvalue 인자(임시 객체 같은 prvalue 또는 std::move가 생성한 xvalue)로 호출될 때 오버로드 해석에 의해 선택돼요. 인자가 리소스를 소유한 객체를 식별한다면, 이 오버로드들은 인자가 보유한 리소스를 이동할 수 있는 옵션을 가지지만 필수는 아니에요. 예를 들어, 연결 리스트의 이동 생성자는 리스트의 헤드 포인터를 복사하고 인자에는 nullptr을 저장하는 대신 개별 노드를 할당하거나 복사하지 않을 수 있어요.

rvalue 참조 변수의 이름은 lvalue이며, rvalue 참조 매개변수를 받는 함수 오버로드에 바인딩되려면 xvalue로 변환되어야 해요. 그래서 이동 생성자와 이동 대입 연산자는 일반적으로 std::move를 사용해요:

// Simple move constructor
A(A&& arg) : member(std::move(arg.member)) // the expression "arg.member" is lvalue
{}

// Simple move assignment operator
A& operator=(A&& other)
{
    member = std::move(other.member);
    return *this;
}

한 가지 예외는 함수 매개변수의 타입이 전달 참조(forwarding reference)인 경우인데, 이는 타입 템플릿 매개변수에 대한 rvalue 참조처럼 보여요. 이 경우에는 std::move 대신 std::forward가 사용돼요.

별도로 명시되지 않는 한, 이동된 모든 표준 라이브러리 객체는 "유효하지만 불특정 상태(valid but unspecified state)"에 놓여요. 즉, 객체의 클래스 불변식이 유지된다는 뜻이에요. 따라서 이동된 후에도 대입 연산자처럼 전제 조건이 없는 함수는 안전하게 사용할 수 있어요:

std::vector<std::string> v;
std::string str = "example";
v.push_back(std::move(str)); // str is now valid but unspecified
str.back(); // undefined behavior if size() == 0: back() has a precondition !empty()
if (!str.empty())
    str.back(); // OK, empty() has no precondition and back() precondition is met

str.clear(); // OK, clear() has no preconditions

또한, xvalue 인자로 호출되는 표준 라이브러리 함수는 그 인자가 객체에 대한 유일한 참조라고 가정할 수 있어요. std::move로 lvalue에서 생성된 경우에도 별칭 검사는 수행되지 않아요. 하지만 표준 라이브러리 타입의 자기 이동 대입(self-move-assignment)은 객체를 유효한(보통 불특정) 상태로 만드는 것이 보장돼요:

std::vector<int> v = {2, 3, 3};
v = std::move(v); // the value of v is unspecified

예제 (Example)

#include <iomanip>
#include <iostream>
#include <string>
#include <utility>
#include <vector>

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

    // uses the push_back(const T&) overload, which means
    // we'll incur the cost of copying str
    v.push_back(str);
    std::cout << "After copy, str is " << std::quoted(str) << '\n';

    // uses the rvalue reference push_back(T&&) overload,
    // which means no strings will be copied; instead, the contents
    // of str will be moved into the vector. This is less
    // expensive, but also means str might now be empty.
    v.push_back(std::move(str));
    std::cout << "After move, str is " << std::quoted(str) << '\n';

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

가능한 출력 (Possible output):

After copy, str is "Salut"
After move, str is ""
The contents of the vector are {"Salut", "Salut"}

같이 보기 (See also)

forward (C++11) 함수 인자를 전달하고 타입 템플릿 인자를 사용해 값 카테고리를 보존해요 (함수 템플릿) [편집]
move_if_noexcept (C++11) 이동 생성자가 예외를 던지지 않으면 인자를 xvalue로 변환해요 (함수 템플릿) [편집]
move (C++11) 요소 범위를 새 위치로 이동해요 (함수 템플릿 & 알고리즘 함수 객체) [편집]
ranges::move (C++20)

더 알아보기 (Learn more)

cppreference