**이동 의미론(Move Semantics)**은 C++11에서 도입된 개념으로, 객체의 리소스를 복사하지 않고 이동시켜 성능을 향상시키는 메커니즘입니다. 기존의 복사 의미론과 대비되는 개념입니다.
class MyString {
char* data;
size_t size;
public:
// 복사 생성자
MyString(const MyString& other) {
size = other.size;
data = new char[size + 1]; // 새로운 메모리 할당
strcpy(data, other.data); // 데이터 복사
std::cout << "복사 생성자 호출" << std::endl;
}
// 복사 대입 연산자
MyString& operator=(const MyString& other) {
if (this != &other) {
delete[] data; // 기존 메모리 해제
size = other.size;
data = new char[size + 1]; // 새로운 메모리 할당
strcpy(data, other.data); // 데이터 복사
}
return *this;
}
};
// 사용 예시 - 비효율적
MyString createString() {
MyString temp("Hello World");
return temp; // 복사 발생! (RVO가 없다면)
}
MyString str = createString(); // 또 복사 발생!
class MyString {
char* data;
size_t size;
public:
// 이동 생성자
MyString(MyString&& other) noexcept {
data = other.data; // 포인터만 이동
size = other.size;
other.data = nullptr; // 원본을 안전한 상태로
other.size = 0;
std::cout << "이동 생성자 호출" << std::endl;
}
// 이동 대입 연산자
MyString& operator=(MyString&& other) noexcept {
if (this != &other) {
delete[] data; // 기존 리소스 해제
data = other.data; // 포인터 이동
size = other.size;
other.data = nullptr; // 원본 초기화
other.size = 0;
}
return *this;
}
};
void func(MyString& lvalue_ref) { // lvalue 참조
std::cout << "lvalue 버전" << std::endl;
}
void func(MyString&& rvalue_ref) { // rvalue 참조 (C++11)
std::cout << "rvalue 버전 - 이동!" << std::endl;
}
MyString str("hello");
func(str); // lvalue 버전 호출
func(MyString("world")); // rvalue 버전 호출
func(std::move(str)); // rvalue 버전 호출 (강제 이동)
// 이동이 일어나는 경우들
MyString str1("Hello");
MyString str2 = std::move(str1); // 명시적 이동
MyString str3 = createString(); // 임시 객체 이동
MyString str4 = MyString("World"); // 직접 구성, 이동
#include <chrono>
#include <vector>
class HeavyObject {
std::vector<int> data;
public:
HeavyObject() : data(1000000, 42) {} // 큰 데이터
// 복사 생성자
HeavyObject(const HeavyObject& other) : data(other.data) {
std::cout << "복사: 비용이 큰 작업" << std::endl;
}
// 이동 생성자
HeavyObject(HeavyObject&& other) noexcept : data(std::move(other.data)) {
std::cout << "이동: 빠른 작업" << std::endl;
}
};
// 성능 테스트
void performance_test() {
std::vector<HeavyObject> container;
// 복사를 통한 추가 (느림)
HeavyObject obj1;
container.push_back(obj1); // 복사 발생
// 이동을 통한 추가 (빠름)
HeavyObject obj2;
container.push_back(std::move(obj2)); // 이동 발생
// 임시 객체 추가 (자동 이동)
container.push_back(HeavyObject()); // 자동으로 이동
}
std::vector<std::string> create_vector() {
std::vector<std::string> vec;
vec.push_back("Hello");
vec.push_back("World");
return vec; // 이동으로 반환 (또는 RVO)
}
std::vector<std::string> v1 = create_vector(); // 이동
std::vector<std::string> v2 = std::move(v1); // 명시적 이동
// v1은 이제 빈 상태
#include <memory>
std::unique_ptr<int> create_ptr() {
return std::make_unique<int>(42); // 이동으로 반환
}
auto ptr1 = create_ptr(); // 이동
auto ptr2 = std::move(ptr1); // 소유권 이동
// ptr1은 이제 nullptr