[C++] Move semantics

C++11 이후부터 이동 생성자라는 것이 생겼는데, 사용법을 간단하게 살펴보면

//이동 생성자
Test(Test &&test) {
    data = test.data;
    test.data = nullptr;    //이동 후, 다시는 기존의 변수를 사용하지 않을 목적.
}

//복사 생성자
Test(const Test &test) {
    ...
}

이런식으로 참조자(&)를 사용해서 클래스 내부에 정의해줄 수 있다.
불필요한 복사와 임시 변수를 최대한 없애기 위한 과정에서 탄생하였다고 한다.
더 이상 사용하지 않을 변수를 포인터를 활용하여 바꿔치기 한다. (소유권 이전)


클래스에서 생성자를 정의할 때, 복사 생성자도 같이 정의하는 경우가 많다.
STL에 있는 자료구조에 이 사용자 정의한 클래스 객체들을 초기화할 때를 생각하면

vector<Test> v;
v.push_back(test1);
v.push_back(test2);
...

이런식으로 넣게 되는데, 이 때 push하는 과정에서 v의 사이즈를 필요할 때마다 늘리므로
기존의 데이터를 옆 칸으로 복사하는 과정이 필요하다.
그러나 이동 생성자가 정의되어 있으므로 이 과정에서 복사가 일어나지 않게 되어 낭비를 막는다.


이러한 취지에서 move()라는 함수가 있다.
move()는 인자를 받아서 'r-value 참조자' 형태로 바꿔주는 역할을 하는데,
('r-value 참조자'는 위에서 이동 생성자를 정의할 때, 매개변수로 작성하였던 모습이다.)
이 함수를 이용하면, 불필요한 낭비없이 초기화가 가능하다.

v.push_back(std::move(test));    //더 이상 test를 사용하지 않음을 유의


여기에 더해 한번 더 최적화를 할 수 있는 방법이 있다.
push_back() 대신 emplace_back() 이라는 함수를 사용하는 것이다.
emplace_back()은 객체를 생성하여 전달하지 않고
컨테이너 내부에서 처리하여 불필요한 '생성자 호출-소멸자 호출'을 하지 않는다.



정리하면, 이동 생성자가 작동하는 경우는 다음과 같다.

1. v.push_back(std::move(test));    //move를 이용해 바꿔줄 때

2. v.push_back(test1 + test2);    //임시변수에 대해서도 이동 생성자로 작동

3. v.push_back(test1);
   v.push_back(test2);
   ...
   v.push_back(testN);
   //내부에서 용량을 늘리는 과정에서 기존의 것들이 임시변수가 되어 이동 생성자로 작동

4. v.emplace_back(std::move(test1));

5. v.emplace_back(test1 + test2);    //임시변수에 대해서 이동 생성자로 작동



댓글

이 블로그의 인기 게시물

[PS] BOJ 20543번 폭탄 던지는 태영이

프로그래밍에서 실수형의 부정확성

프로그래머스 2019 윈터코딩 온라인 테스트를 보았다. (풀이)