Move 문법과 perfect forwarding

은수·2022년 6월 27일

cpp study

목록 보기
15/21

move 함수 (move semantics)

move 함수

  • 좌측값을 우측값으로 바꿔주는 함수
  • 이동생성이기 때문에 기존의 복사 생성보다 빠르게 수행

std::move 함수는 이동을 수행하지 않음. 그냥 인자로 받은 객체를 우측값으로 변환할 뿐임.
--> 즉, 타입 변환만 수행

#include <iostream>
#include <utility>

class A {
 public:
  A() { std::cout << "일반 생성자 호출!" << std::endl; }
  A(const A& a) { std::cout << "복사 생성자 호출!" << std::endl; }
  A(A&& a) { std::cout << "이동 생성자 호출!" << std::endl; }
};

int main() {
  // 일반 생성자 호출
  A a;
  
  // 복사 생성자 호출
  // b(a)했을 때 a가 좌측값이므로 좌측값 레퍼런스 참조하기 때문
  std::cout << "---------" << std::endl;
  A b(a);

  // 이동 생성자 호출
  // std::move 함수가 인자로 받은 객체를 우측값으로 변환해서 리턴해주기 때문.
  std::cout << "---------" << std::endl;
  A c(std::move(a));
}


Perfect forwarding

cpp의 템플릿

  • 타입을 정하지 않은 것으로 코드에 유연성을 제공함.
  • 템플릿 함수에 Lvalue나 Rvalue를 넘겨줄 수 있음 > 문제 발생

이 때, std::forward<T>(u) 사용!

  • 문맥에 따라 &Lvalue, &&Rvalue를 구분하지 못하는 경우 std::forward를 통해 이를 분명하게 해줌

참고 :
C++ 컴파일러가 템플릿 타입을 추론할 때, 템플릿 인자 T 가 레퍼런스가 아닌 일반적인 타입이라면 const 를 무시함

#include <iostream>

template<class T>
void print(T& n) {
    std::cout << "l-value" << std::endl;
}

template<class T>
void print(const T& n) {
    std::cout << "r-value" << std::endl;
}

template<class T>
void fnc(T&& n) {
    print(std::forward<T>(n));
}

int main() {
    int n = 10;
    fnc(n);  // lvalue
    fnc("hwan"); // rvalue
    fnc(1.123); // rvalue
    
    return 1;
}

출처 : https://hwan-shell.tistory.com/250


보편적 레퍼런스 (Universal reference)

보편적 레퍼런스

  • 템플릿 인자 T에 대해서, 우측값 레퍼런스를 받는 형태
  • 우측값만 받는 레퍼런스와는 다름
  • 보편적 레퍼런스는 좌측값 역시 받아낼 수 있기 때문
  • 레퍼런스 겹침 규칙 (reference collapsing rule) 에 따라 T 의 타입을 추론
#include <iostream>

// T&& 보편적 레퍼런스 forward 함수
template <typename T>
void wrapper(T&& u) {
  g(std::forward<T>(u));
}

class A {};

void g(A& a) { std::cout << "좌측값 레퍼런스 호출" << std::endl; }
void g(const A& a) { std::cout << "좌측값 상수 레퍼런스 호출" << std::endl; }
void g(A&& a) { std::cout << "우측값 레퍼런스 호출" << std::endl; }

int main() {
  A a;
  const A ca;

  std::cout << "원본 --------" << std::endl;
  g(a);
  g(ca);
  g(A());

  std::cout << "Wrapper -----" << std::endl;
  wrapper(a);
  wrapper(ca);
  wrapper(A());
}

0개의 댓글