INTRO
int total {0};
total = 100 + 200;
위 코드에서 total은 포인터로 접근할 수 있는 변수 값, L-Value입니다.
그리고 total에 할당되는 100+200 수식은 포인터로 접근할 수 없는 R-Value입니다.
C++에서 이런 값들은 이름없는 temp value로 일시적으로 저장되었다가,
total과 같은 값에 복사 저장되고 난 뒤 제거됩니다.
그리고 같은 일이 temp value를 temp object로만 바뀌어서 객체에서도 발생합니다.
복사 생성자를 생각하시면 됩니다.
그런데, 복사 생성자를 반복적으로 호출하게 되면 temporary object가 그만큼 많이 생성됩니다.
반면 객체는 상대적으로 메모리를 많이 요구합니다.
Deep copy를 행하면 더욱 많이 요구되겠죠?
이런 이유에서 Move Semantics, Move Constructor (이동 생성자) 가 등장합니다.
이를 이해하기 위해서는 우선 R-Value References에 대해서 이해해야합니다.
L-Value References와는 다르게 r-value references는 double ampersand(&&) 를 사용합니다.
직관적인 예시를 살펴보겠습니다.
int x{100};
int &l_ref = x; // l-value reference
l_ref = 50;
int &&r_ref = 500; // r-value reference
r_ref = 300;
int &&x_ref = x; // COMPILER ERROR
&l_ref 는 single ampersand로 선언되었기 때문에 l-value인 x를 값으로 지닐 수 있습니다.
&&r_ref는 double ampersand로 선언되었기 때문에 r-value인 500을 값으로 지닐 수 있습니다.
&&로 선언된 x_ref에 x를 저장하려고 하면 l-value 이기 때문에 컴파일 오류가 발생합니다.
함수에서도 동일하게 적용됩니다.
int x {100};
void func(int &&num);
func(200); // OK
func(x); // COMPILE ERROR
r-value reference를 인자로 받는 func에 정수를 직접 입력하면 문제가 없지만,
l-value인 변수를 입력하면 오류가 발생합니다.
여기까지 이해하고 이동 생성자를 자세히 살펴보겠습니다.
Move Constructor (이동 생성자)
이동 생성자는 객체를 복사하지 않고 이동시킵니다.
그리고 이것은 메모리적인 측면에서 매우 효율적입니다.
이동 생성자의 프로토타입들을 살펴보겠습니다.
Type::Type(Type &&source);
Player::Player(Player &&source);
Move::Move(Move &&source);
기존에 사용하던 복사 생성자와 유사하게 구조되어 있습니다.
첫번째 차이점은 const 키워드가 없다는 점입니다.
원본 객체의 포인터를 null 으로 변경해야 하기 때문입니다.
두번째는 입력 인자로 R-Value Reference 를 받는다는 점입니다.
Double ampersand(&&)로 확인됩니다.
이 이동 생성자들의 구조는 간단합니다.
Move::Move(Move &&source) noexcept : data(source.data) { source.data = nullptr; }
Deep copying으로 인한 큰 메모리 요구없이
기존의 source.data가 지칭하던 주소의 소유권을 새로운 객체의 data값에 이전시킵니다.
즉, 복사를 통해 객체를 생성할 때의 불가피한 메모리 소요 없이 새로운 객체를 만들어낼 수 있습니다.
중요한 점은 source.data = nullptr; 을 통해서 기존의 값을 null로 변경하는 것 입니다.
nullptr로 변경해주지 않는다면 shallow copying과 동일한 행동입니다.
'C++ > 객체지향 프로그래밍 (OOP)' 카테고리의 다른 글
[C++] 상수 클래스 | Using const with Classes (0) | 2024.01.02 |
---|---|
[C++] this keyword | this 포인터 (0) | 2024.01.02 |
[C++] Shallow Copying & Deep Copying | 얕은 복사 & 깊은 복사 (1) | 2023.12.29 |
[C++] 클래스 멤버 접근 제한자 | Class Member Access Modifiers (1) | 2023.12.29 |
[C++] 함수 혹은 메소드에서 객체의 불필요한 복사를 방지하기 (0) | 2023.12.29 |