모두의 코드
C++ 레퍼런스 - std::move 함수

작성일 : 2019-09-26 이 글은 1320 번 읽혔습니다.

아직 C++ 에 친숙하지 않다면 씹어먹는 C++ 은 어때요?

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 된 객체를 함수에 전달한다면, 우측값 레퍼런스를 인자로 받는 함수(예를 들어서 이동 생성자, 이동 대입 연산자, vectorpush_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 : 생성자가 예외를 던지지 않을 경우에만 우측값 레퍼런스를 얻는다.

첫 댓글을 달아주세요!
프로필 사진 없음
강좌에 관련 없이 궁금한 내용은 여기를 사용해주세요