본문 바로가기
-----ETC-----/C++ 고급 프로그래밍과 응용 프로젝트 시리즈

[C++ 고급 프로그래밍과 응용 프로젝트 시리즈] Day 7: R-값 참조와 이동 시멘틱

by cogito21_cpp 2024. 8. 1.
반응형

R-값 참조 (Rvalue References)

R-값 참조는 C++11에서 도입된 기능으로, 임시 객체나 이동할 수 있는 리소스를 참조하는 데 사용됩니다. R-값 참조를 사용하면 불필요한 복사 연산을 줄이고, 성능을 최적화할 수 있습니다.

 

R-값 참조의 기본 사용법

R-값 참조는 && 연산자를 사용하여 정의됩니다.

#include <iostream>

void printValue(int& x) {
    std::cout << "L-value reference: " << x << std::endl;
}

void printValue(int&& x) {
    std::cout << "R-value reference: " << x << std::endl;
}

int main() {
    int a = 10;
    printValue(a);       // L-value reference
    printValue(20);      // R-value reference
    printValue(a + 30);  // R-value reference

    return 0;
}

 

이 예제에서 printValue 함수는 L-값 참조와 R-값 참조를 모두 처리할 수 있습니다. a는 L-값으로, 20a + 30은 R-값으로 전달됩니다.


이동 시멘틱 (Move Semantics)

이동 시멘틱은 R-값 참조를 활용하여 객체의 소유권을 이전하는 방법입니다. 이를 통해 불필요한 복사 연산을 피하고, 성능을 향상시킬 수 있습니다.

 

std::move

std::move는 객체를 R-값으로 캐스팅하여 이동 시멘틱을 적용할 수 있도록 합니다.

#include <iostream>
#include <utility>  // std::move

class MyClass {
public:
    int* data;

    MyClass(int size) : data(new int[size]) {
        std::cout << "Constructor: allocated " << size << " ints." << std::endl;
    }

    ~MyClass() {
        delete[] data;
        std::cout << "Destructor: freed memory." << std::endl;
    }

    // 복사 생성자
    MyClass(const MyClass& other) : data(new int[1]) {
        std::cout << "Copy constructor." << std::endl;
    }

    // 이동 생성자
    MyClass(MyClass&& other) noexcept : data(other.data) {
        other.data = nullptr;
        std::cout << "Move constructor." << std::endl;
    }
};

int main() {
    MyClass obj1(10);
    MyClass obj2 = std::move(obj1);  // 이동 생성자 호출

    return 0;
}

 

이 예제에서 MyClass는 이동 생성자를 정의하여 객체의 소유권을 이전합니다. std::move를 사용하여 obj1의 리소스를 obj2로 이동시킵니다.

 

이동 대입 연산자

이동 대입 연산자는 이동 시멘틱을 사용하여 객체를 대입하는 연산자입니다.

#include <iostream>
#include <utility>  // std::move

class MyClass {
public:
    int* data;

    MyClass(int size) : data(new int[size]) {
        std::cout << "Constructor: allocated " << size << " ints." << std::endl;
    }

    ~MyClass() {
        delete[] data;
        std::cout << "Destructor: freed memory." << std::endl;
    }

    // 복사 생성자
    MyClass(const MyClass& other) : data(new int[1]) {
        std::cout << "Copy constructor." << 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 operator." << std::endl;
        }
        return *this;
    }
};

int main() {
    MyClass obj1(10);
    MyClass obj2(20);
    obj2 = std::move(obj1);  // 이동 대입 연산자 호출

    return 0;
}

 

이 예제에서 MyClass는 이동 대입 연산자를 정의하여 객체의 소유권을 이전합니다. std::move를 사용하여 obj1의 리소스를 obj2로 이동시킵니다.


완벽한 전달 (Perfect Forwarding)

완벽한 전달은 템플릿 함수를 통해 인자를 그대로 전달하는 기법입니다. 이를 통해 인자의 타입과 값 카테고리를 유지할 수 있습니다.

 

완벽한 전달 예제

#include <iostream>
#include <utility>  // std::forward

void process(int& x) {
    std::cout << "L-value reference process: " << x << std::endl;
}

void process(int&& x) {
    std::cout << "R-value reference process: " << x << std::endl;
}

template <typename T>
void forwarder(T&& x) {
    process(std::forward<T>(x));
}

int main() {
    int a = 10;
    forwarder(a);       // L-value reference process
    forwarder(20);      // R-value reference process
    forwarder(std::move(a)); // R-value reference process

    return 0;
}

이 예제에서 forwarder 템플릿 함수는 std::forward를 사용하여 인자를 그대로 전달합니다. 이를 통해 인자의 타입과 값 카테고리를 유지할 수 있습니다.


실습 문제

문제 1: R-값 참조를 사용하여 벡터의 요소를 이동

R-값 참조를 사용하여 벡터의 요소를 다른 벡터로 이동하는 프로그램을 작성하세요.

 

해설:

#include <iostream>
#include <vector>
#include <utility>  // std::move

int main() {
    std::vector<int> vec1 = {1, 2, 3, 4, 5};
    std::vector<int> vec2;

    for (int& x : vec1) {
        vec2.push_back(std::move(x));
    }

    std::cout << "vec2: ";
    for (const int& x : vec2) {
        std::cout << x << " ";
    }
    std::cout << std::endl;

    std::cout << "vec1: ";
    for (const int& x : vec1) {
        std::cout << x << " ";
    }
    std::cout << std::endl;

    return 0;
}

 

문제 2: 이동 생성자와 이동 대입 연산자를 정의하여 객체를 이동

이동 생성자와 이동 대입 연산자를 정의하여 객체를 이동하는 클래스를 작성하세요.

 

해설:

#include <iostream>
#include <utility>  // std::move

class MyClass {
public:
    int* data;

    MyClass(int size) : data(new int[size]) {
        std::cout << "Constructor: allocated " << size << " ints." << std::endl;
    }

    ~MyClass() {
        delete[] data;
        std::cout << "Destructor: freed memory." << 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 operator." << std::endl;
        }
        return *this;
    }
};

int main() {
    MyClass obj1(10);
    MyClass obj2 = std::move(obj1);  // 이동 생성자 호출

    MyClass obj3(20);
    obj3 = std::move(obj2);          // 이동 대입 연산자 호출

    return 0;
}

 

문제 3: 완벽한 전달을 사용하여 다양한 타입의 인자를 처리

완벽한 전달을 사용하여 다양한 타입의 인자를 처리하는 템플릿 함수를 작성하세요.

 

해설:

#include <iostream>
#include <utility>  // std::forward

void process(int& x) {
    std::cout << "L-value reference process: " << x << std::endl;
}

void process(int&& x) {
    std::cout << "R-value reference process: " << x << std::endl;
}

template <typename T>
void forwarder(T&& x) {
    process(std::forward<T>(x));


}

int main() {
    int a = 10;
    forwarder(a);       // L-value reference process
    forwarder(20);      // R-value reference process
    forwarder(std::move(a)); // R-value reference process

    return 0;
}

 

이제 7일차의 학습을 마쳤습니다. R-값 참조와 이동 시멘틱에 대해 상세히 학습하고 실습 문제를 풀어보았습니다.

 

질문이나 피드백이 있으면 언제든지 댓글로 남겨 주세요. 내일부터는 "디자인 패턴 심화"에 대해 다루겠습니다. 내일은 "싱글톤 패턴"에 대해 학습하겠습니다.

반응형