[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); //임시변수에 대해서 이동 생성자로 작동
//이동 생성자
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); //임시변수에 대해서 이동 생성자로 작동
댓글
댓글 쓰기