VisualStudio/C++

[C++] && 오른 값 참조(move)와 보편 참조(forward)

usingsystem 2024. 6. 4. 12:56
728x90

1. 오른값 참조 (Rvalue reference)

기본적으로 왼값(lvalue)은 메모리에 지속적으로 존재하는 객체를 가리키는 표현식이며, 오른값(rvalue)은 메모리에서 임시로 생성되거나 이동할 수 있는 객체를 가리키는 표현식입니다.

오른값 참조는 기존의 왼값 참조와 구분하기 위해 Type&& 형태로 표기됩니다. 객체의 내용을 다른 객체로 이동하여 복사 비용을 최소화하고 성능을 향상시키는 기법입니다. 이를 통해 객체를 복사하는 대신 소유권을 이동시켜 효율적으로 작업할 수 있습니다.

 

 

Type&& 형태로 사용되며, Type은 임의의 타입을 나타냅니다. 오른값 참조는 오른값(임시 객체나 이동 가능한 객체)에만 바인딩됩니다.

#include <iostream>
#include <utility>

void process(int&& value) {
    std::cout << "Received rvalue: " << value << std::endl;
}

int main() {
    int x = 42;
    process(std::move(x)); // x의 소유권을 이동하여 전달

    return 0;
}

위의 예시에서 process() 함수는 int&& value 형태로 오른값 참조를 인자로 받습니다. main() 함수에서 x 변수를 std::move() 함수를 통해 오른값으로 변환하여 process() 함수로 전달합니다. 이것은 x의 소유권을 process() 함수로 이동시킵니다.

2. 보편 참조 (Universal reference)

Type&& 형태로 사용되며, Type은 템플릿의 형식 인자(template parameter)입니다. 보편 참조는 템플릿 함수나 생성자에서 사용되며, 왼값과 오른값 모두를 받을 수 있습니다.

#include <iostream>
#include <utility>

template<typename T>
void foo(T&& arg) {
    std::cout << "Received argument: " << arg << std::endl;
}

int main() {
    int x = 42;
    foo(x); // 왼값 전달
    foo(100); // 오른값 전달

    return 0;
}

위의 예시에서 foo() 함수는 T&& arg 형태로 보편 참조를 인자로 받습니다. main() 함수에서 foo() 함수를 호출할 때 왼값 x와 오른값 100을 인자로 전달합니다. foo() 함수는 템플릿 함수이므로 컴파일러는 인자의 타입에 따라 적절한 참조를 결정합니다.

std::move

std::move 함수는 주어진 객체를 오른값으로 캐스팅합니다. 이것은 주로 다른 함수로 객체의 소유권을 이동시킬 때 사용됩니다. 이 함수는 객체를 복사하는 대신 이동시켜 성능을 향상시키는데 사용됩니다.

#include <utility>

// 예시: 객체의 소유권을 이동시키는 함수
void process(MyObject&& obj) {
    // obj 처리
}

int main() {
    MyObject obj;
    process(std::move(obj)); // obj의 소유권을 이동시킴

    return 0;
}

std::forward

std::forward 함수는 보편 참조(Universal reference)를 제대로 보전하기 위해 사용됩니다. 이 함수는 주어진 객체를 보편 참조 형식으로 캐스팅합니다. 이 함수는 주로 템플릿 함수나 템플릿 생성자에서 사용되며, 템플릿 인자를 그대로 전달할 때 사용됩니다.

#include <utility>

// 예시: 보편 참조를 받아 다른 함수로 전달하는 함수
template<typename T>
void relay(T&& arg) {
    // arg를 다른 함수로 전달할 때 std::forward 사용
    some_function(std::forward<T>(arg));
}

int main() {
    MyObject obj;
    relay(obj); // obj를 전달할 때 std::forward 사용

    return 0;
}

std::forward<T>(arg)는 arg의 타입을 보존하여 다른 함수로 전달합니다. 이렇게 함으로써 보편 참조를 제대로 유지하면서 객체를 전달할 수 있습니다. 만약 std::forward를 사용하지 않고 단순히 arg를 전달하면 왼값 레퍼런스로 취급되어 객체의 복사가 발생할 수 있습니다.

728x90