반응형
Move Semantics와 R-값 참조의 중요성
C++11에서 도입된 Move Semantics(이동 시멘틱스)와 R-값 참조는 자원의 이동을 통해 성능을 최적화할 수 있는 강력한 도구입니다. 특히, 객체의 복사가 빈번하게 발생하는 상황에서 큰 성능 향상을 가져올 수 있습니다.
R-값 참조
R-값 참조는 임시 객체와 같이 수명이 짧은 값을 가리키는 참조입니다. R-값 참조를 통해 객체를 복사하지 않고 이동할 수 있습니다. 이를 통해 불필요한 복사를 방지하고, 자원 관리 효율을 높일 수 있습니다.
int&& rvalue = 10;
Move Semantics
이동 시멘틱스는 복사 대신 자원을 이동하는 기법입니다. 이동 생성자와 이동 할당 연산자를 사용하여 구현할 수 있습니다.
이동 생성자
#include <iostream>
class MyClass {
public:
int* data;
MyClass() : data(new int[1000]) {
std::cout << "Constructor" << std::endl;
}
~MyClass() {
delete[] data;
std::cout << "Destructor" << std::endl;
}
// 이동 생성자
MyClass(MyClass&& other) noexcept : data(other.data) {
other.data = nullptr;
std::cout << "Move Constructor" << std::endl;
}
// 이동 할당 연산자
MyClass& operator=(MyClass&& other) noexcept {
if (this != &other) {
delete[] data;
data = other.data;
other.data = nullptr;
std::cout << "Move Assignment" << std::endl;
}
return *this;
}
// 복사 생성자와 복사 할당 연산자 삭제
MyClass(const MyClass&) = delete;
MyClass& operator=(const MyClass&) = delete;
};
MyClass createObject() {
MyClass obj;
return obj; // 이동 생성자가 호출됩니다.
}
int main() {
MyClass obj1 = createObject(); // 이동 생성자가 호출됩니다.
MyClass obj2;
obj2 = std::move(obj1); // 이동 할당 연산자가 호출됩니다.
return 0;
}
std::move와 std::forward
std::move
std::move
는 객체를 R-값 참조로 캐스팅하여 이동 시멘틱스를 사용할 수 있게 합니다.
MyClass obj1;
MyClass obj2 = std::move(obj1); // 이동 생성자 호출
std::forward
std::forward
는 완벽한 전달(perfect forwarding)을 구현하는 데 사용됩니다. 이는 템플릿 함수에서 인자를 원래의 L-값 또는 R-값으로 전달할 때 유용합니다.
#include <iostream>
#include <utility>
void process(int& lval) {
std::cout << "L-value reference" << std::endl;
}
void process(int&& rval) {
std::cout << "R-value reference" << std::endl;
}
template<typename T>
void forwarder(T&& arg) {
process(std::forward<T>(arg));
}
int main() {
int x = 10;
forwarder(x); // L-value 전달
forwarder(10); // R-value 전달
return 0;
}
실습 문제
문제 1: 이동 시멘틱스를 사용하여 성능 최적화
다음 코드에서 이동 시멘틱스를 사용하여 성능을 최적화하세요.
main.cpp
#include <iostream>
#include <vector>
class MyClass {
public:
int* data;
MyClass() : data(new int[1000]) {
std::cout << "Constructor" << std::endl;
}
~MyClass() {
delete[] data;
std::cout << "Destructor" << std::endl;
}
// 복사 생성자
MyClass(const MyClass& other) : data(new int[1000]) {
std::copy(other.data, other.data + 1000, data);
std::cout << "Copy Constructor" << std::endl;
}
// 복사 할당 연산자
MyClass& operator=(const MyClass& other) {
if (this != &other) {
std::copy(other.data, other.data + 1000, data);
std::cout << "Copy Assignment" << std::endl;
}
return *this;
}
};
MyClass createObject() {
MyClass obj;
return obj;
}
int main() {
MyClass obj1 = createObject();
MyClass obj2 = obj1;
return 0;
}
해답:
main.cpp (최적화)
#include <iostream>
#include <vector>
class MyClass {
public:
int* data;
MyClass() : data(new int[1000]) {
std::cout << "Constructor" << std::endl;
}
~MyClass() {
delete[] data;
std::cout << "Destructor" << std::endl;
}
// 이동 생성자
MyClass(MyClass&& other) noexcept : data(other.data) {
other.data = nullptr;
std::cout << "Move Constructor" << std::endl;
}
// 이동 할당 연산자
MyClass& operator=(MyClass&& other) noexcept {
if (this != &other) {
delete[] data;
data = other.data;
other.data = nullptr;
std::cout << "Move Assignment" << std::endl;
}
return *this;
}
// 복사 생성자와 복사 할당 연산자 삭제
MyClass(const MyClass&) = delete;
MyClass& operator=(const MyClass&) = delete;
};
MyClass createObject() {
MyClass obj;
return obj;
}
int main() {
MyClass obj1 = createObject(); // 이동 생성자가 호출됩니다.
MyClass obj2 = std::move(obj1); // 이동 생성자가 호출됩니다.
return 0;
}
이제 여덟 번째 날의 학습을 마쳤습니다. Move semantics와 R-값 참조의 중요성을 이해하고, 실습 문제를 통해 이를 적용하는 방법을 학습했습니다.
질문이나 피드백이 있으면 언제든지 댓글로 남겨 주세요. 내일은 "완벽한 전달 (perfect forwarding)"에 대해 학습하겠습니다.
반응형
'-----ETC----- > C++ 성능 최적화 및 고급 테크닉 시리즈' 카테고리의 다른 글
[C++ 성능 최적화 및 고급 테크닉] Day 10: inline 함수와 매크로의 사용 (0) | 2024.08.01 |
---|---|
[C++ 성능 최적화 및 고급 테크닉] Day 7: 데이터 로컬리티와 캐시 친화적 코딩 (0) | 2024.08.01 |
[C++ 성능 최적화 및 고급 테크닉] Day 5: 메모리 관리 최적화 (0) | 2024.08.01 |
[C++ 성능 최적화 및 고급 테크닉] Day 6: 불필요한 복사 방지 (copy elision) (0) | 2024.08.01 |
[C++ 성능 최적화 및 고급 테크닉] Day 3: 코드 프로파일링 및 벤치마킹 (0) | 2024.08.01 |