C++ 이동 의미론(Move Semantics, C++11)은 불필요한 복사 없이 자원을 이전할 수 있게 한다. 우측값 참조(&&)를 통해 임시 객체의 자원을 "훔쳐" 성능을 향상시킨다.
좌측값 vs 우측값
cpp
int x = 42; // x: 좌측값 (lvalue), 42: 우측값 (rvalue)
int& lr = x; // 좌측값 참조
int&& rr = 42; // 우측값 참조
std::string s1 = "hello";
std::string s2 = std::move(s1); // s1을 s2로 이동
// s1은 유효하지만 비어있는 상태
이동 생성자 / 이동 대입
cpp
class Buffer {
size_t size;
char* data;
public:
// 복사 생성자: 깊은 복사 (비용 높음)
Buffer(const Buffer& other) : size(other.size), data(new char[other.size]) {
std::copy(other.data, other.data + size, data);
}
// 이동 생성자: 포인터만 이전 (O(1))
Buffer(Buffer&& other) noexcept : size(other.size), data(other.data) {
other.size = 0;
other.data = nullptr; // 원본을 null로
}
~Buffer() { delete[] data; }
};
std::move와 std::forward
cpp
// std::move: 무조건 우측값으로 캐스팅
template<typename T>
void transfer(T&& val) {
vec.push_back(std::move(val)); // 이동
}
// std::forward: 완벽한 전달 (퍼펙트 포워딩)
template<typename T>
void wrapper(T&& val) {
actual_func(std::forward<T>(val)); // lvalue면 lvalue로, rvalue면 rvalue로
}
5의 법칙 (Rule of Five)
소멸자를 정의하면 이동/복사 연산도 직접 정의해야 한다:
- 1.소멸자 (
~T()) - 2.복사 생성자
- 3.복사 대입 연산자
- 4.이동 생성자
- 5.이동 대입 연산자
cpp
// 또는 컴파일러에게 위임
Buffer(Buffer&&) = default;
Buffer& operator=(Buffer&&) = default;
관련 개념