음악, 삶, 개발
Move Constructor 와 Move Assignment 에 대한 이해 본문
< Move 는 이삿짐 센터다! >
C++ 에서 Move 의 의미는 이삿짐 센터라고 외우자.
현실 세계에서 이사는 한 집의 짐을 다른 집으로 다 옮기는것이지만,
C++ 에서는, 한 집에서의 모든 값을 다른 집에 복사해주고, 복사를 마치면 남의 집의 값을 각 type 이 제공하는 방법으로 초기화하는것이다.
예를 들어 완전히 이해해보자.
< C++ 에서 Move 의 의미 >
T 라는 우리가 만든 클래스가 있다.
strcut T {
int a;
double b;
float c;
}
이 클래스 유형을 가진 두개의 객체 A, B 가 있고 A 를 B 로 Move 한다고 가정해보자.
이때 발생하는 실제 프로세스는 아래와 같다.
1. 객체 A 의 모든 멤버 a, b, c 의 값을, 객체 B 의 멤버 a, b, c, 의 값으로 각각 복사한다.
2. 복사가 끝나면 A 의 모든 멤버 a, b, c 를 default 초기화한다. (각 멤버들의 Type 이 제공하는 방식에 따라)
< 컴파일러가 제공해주는 Move Constructor 와 Move Assignment >
우리가 우리의 클래스안에 Move Constructor 와 Move Assignment 를 따로 정의하지않았을때,
컴파일러가 직접 Move Constructor 와 Move Assignment 를 위의 방식 "원본 복사후, 원본 초기화" 로 정의한다.
대부분의 경우 컴파일러의 선택이 문제가 없지만,
문제가 있는 경우가 있다.
바로 멤버 변수중 const 변수가 있는 경우이다.
struct T {
const int a;
double b;
}
위와 같이, 우리는 객체의 멤버 변수중, 초기화 이후에는 절대 변하면 안되는 값을 가지고자할때가 있다.
T 로 와닿지않는다면 다른 예를 들어보자.
struct Note {
const juce::Uuid id;
}
juce::Uuid 는 객체를 생성했을때 곧 바로 128bits 의 unique 한 id 를 생성해준다.
우리의 각 Note 의 id 는 절대 중복되어서는 안되며, 이 id 가 다른 놈에게 복사되어서도 안된다.
위와 같이 const 멤버인 경우, 당연히 멤버간의 복사는 이루어질수가 없으며,
const 멤버간의 복사를 시도하는 컴파일러가 제공하는 Move Constructor 와 Move assignment 는
당연히 error 이고 컴파일되지않는다.
< const 멤버를 가진 클래스라면, 반드시 우리가 Move 를 정의하자! >
어떻게 정의할까?
간단히 클래스를 만들어보자.
struct T {
const int a {0}
int b {0}
double c {0.0}
float d {0.0f}
}
대부분 우리의 클래스 멤버는 위와 같은 모습일것이다.
1개 내지 2개의 멤버만이 const 이고, 나머지는 non-const 인것이다.
이럴때에 const 멤버 a 는 아무런 조취도 취해지면 안되며,
나머지 멤버는 복사후 초기화 과정을 거치면된다.
코드로 보면 아래와같다.
struct T {
// Move Constructor
T(T&& other) {
// copy other
b = other.b;
c = other.c;
d = other d;
// reset other
other.b = 0;
other.c = 0.0
other.d = 0.0f;
}
// Move Assignment
T& operator= (T&& other) {
// copy other
b = other.b;
c = other.c;
d = other d;
// reset other
other.b = 0;
other.c = 0.0
other.d = 0.0f;
return *this;
}
const int a {0}
int b {0}
double c {0.0}
float d {0.0f}
}
이것만 기억하라.
"복사후 reset"
< Copy Constructor, Copy Assignment vs Move Constructor, Move Assignment >
Copy 녀석들과, 이삿짐센터의 차이를 정리해보자.
1. Copy : 인자가 const T& other
2. Move : 인자가 T&& other
3. Copy 는 Copy 만, Move 는 Copy 후 Reset 까지.
< Move Constructor, Move Assignment 를 반드시 정의해야하는 이유 >
앞서 말했지만, 중요해서 다시 남겨놓는다.
나의 멤버 변수들중 const 가 있다면 반드시 Move 를 둘다 정의해야한다.
이 const 멤버를 제외하고 복사후 reset 이 이루어져야하기때문이다.
C++ 이 제공하는 <algorithm> 의 수많은 함수들이
내부적으로 Move Constructor 와 Move Assignment 를 호출한다.
예를 들어, std::sort() 를 보면 아 Move Constructor 나 Move Assignment 가 호출되겠구나 라고 생각할수있어야한다.
< 마치며 >
나의 멤버 변수중 하나라도 const 가 있다면
곧바로 Copy Constructor, Copy Assignment, Move Constructor, Move Assignment 에 대한 정의를
직접 해야한다. (이 const 멤버 변수를 제외하고 복사가 일어나도록...)