std :: move와 std :: forward의 차이점은 무엇입니까?


160

나는 이것을 보았다 : 기본 생성자 Move Constructor를 호출하는 Move Constructor

누군가 설명 할 수 있습니까?

  1. 차이 std::movestd::forward, 바람직하게는 일부 코드 예에?
  2. 쉽게 생각하는 방법과 사용시기


"쉽게 생각하는 방법과 사용 move시기 " 가치 를 옮기고forward 싶을 때 와 완벽한 전달을 원할 때 사용합니다. 이것은 로켓 과학이 아닙니다.;)
Nicol Bolas

move ()는 전달 된 매개 변수를 기반으로 forward ()이 캐스트를 수행하는 무조건 캐스트를 수행합니다.
RaGa__M

답변:


159

std::move객체를 가져 와서 임시 (rvalue)로 처리 할 수있게합니다. 시맨틱 요구 사항은 아니지만 일반적으로 rvalue에 대한 참조를 승인하는 함수는이를 무효화합니다. 이 표시되면 std::move나중에 개체 값을 사용해서는 안되지만 새 값을 할당하고 계속 사용할 수 있습니다.

std::forward호출자가 전달하는 데 사용한 템플릿 함수 매개 변수 (함수 내부)를 값 범주 (lvalue 또는 rvalue)로 캐스팅하는 단일 사용 사례가 있습니다. 이를 통해 rvalue 인수는 rvalue로 전달되고 lvalue는 "완벽한 전달"이라는 스키마 인 lvalue로 전달됩니다.

하려면 설명 :

void overloaded( int const &arg ) { std::cout << "by lvalue\n"; }
void overloaded( int && arg ) { std::cout << "by rvalue\n"; }

template< typename t >
/* "t &&" with "t" being template param is special, and  adjusts "t" to be
   (for example) "int &" or non-ref "int" so std::forward knows what to do. */
void forwarding( t && arg ) {
    std::cout << "via std::forward: ";
    overloaded( std::forward< t >( arg ) );
    std::cout << "via std::move: ";
    overloaded( std::move( arg ) ); // conceptually this would invalidate arg
    std::cout << "by simple passing: ";
    overloaded( arg );
}

int main() {
    std::cout << "initial caller passes rvalue:\n";
    forwarding( 5 );
    std::cout << "initial caller passes lvalue:\n";
    int x = 5;
    forwarding( x );
}

Howard가 언급했듯이이 두 함수가 단순히 참조 유형으로 캐스트되기 때문에 유사성이 있습니다. 그러나 rvalue 참조 캐스트의 유용성의 99.9 %를 다루는 이러한 특정 사용 사례를 제외하고 static_cast직접 사용 하고 수행중인 작업에 대한 적절한 설명을 작성해야합니다.


나는 확실히 그 것을 정확하지 않다 std::forward'의 유일한 사용 사례는 함수 인수의 완벽한 전달입니다. 객체 멤버와 같은 다른 것을 완벽하게 전달하려는 상황에 처했습니다.
Geoff Romer

@GeoffRomer 파라미터의 멤버? 예가 있습니까?
Potatoswatter

별도의 질문으로 예제를 게시했습니다 : stackoverflow.com/questions/20616958/…
Geoff Romer

흠, 그래서 이것을 올바르게 이해한다면, forward (x)가 x에서 작동하는 것처럼 forward (5)가 5에서 작동하는 것처럼 forward ()가 x에서 작동하는 것처럼 단일 함수 forward ()를 작성할 수 있음을 의미합니다. 과부하를 명시 적으로 쓰지 않고 참조하십시오.
iheanyi

@iheanyi Yep, 그 아이디어입니다! 그러나 일반적인 기능뿐만 아니라 템플릿이어야합니다.
Potatoswatter

63

모두 std::forwardstd::move아무것도하지만, 캐스트를하지 않습니다.

X x;
std::move(x);

위의 내용 x은 X 유형 의 lvalue 표현식 을 X 유형의 rvalue 표현식 (정확한 xvalue)으로 캐스트합니다. movervalue를받을 수도 있습니다 :

std::move(make_X());

이 경우 항등 함수입니다. X 유형의 rvalue를 가져 와서 X 유형의 rvalue를 반환합니다.

함께 std::forward사용하면 어느 정도 대상을 선택할 수 있습니다 :

X x;
std::forward<Y>(x);

xX 유형 의 lvalue 표현식 을 Y 유형의 표현식으로 캐스트합니다 . Y에 대한 제한 사항이 있습니다.

Y는 액세스 가능한 X의 Base이거나 X의 Base에 대한 참조 일 수 있습니다. Y는 X 또는 X에 대한 참조 forward일 수 있습니다. Y는 액세스 가능한 Base 변환을 통한 경우를 제외하고 X에서 간단히 변환 가능한 유형이 될 수 없습니다.

Y가 lvalue 참조이면 결과는 lvalue 표현식이됩니다. Y가 lvalue 참조가 아닌 경우 결과는 rvalue (정확한 xvalue)식이됩니다.

forwardY가 lvalue 참조가 아닌 경우에만 rvalue 인수를 사용할 수 있습니다. 즉, rvalue를 lvalue로 캐스트 할 수 없습니다. 이는 안전상의 이유로 일반적으로 매달려있는 참조로 이어지기 때문입니다. 그러나 rvalue를 rvalue로 캐스팅하는 것은 괜찮으며 허용됩니다.

허용되지 않는 것으로 Y를 지정하려고하면 런타임이 아닌 컴파일시 오류가 발생합니다.


를 사용하여 객체를 함수에 완벽하게 전달하면 std::forward해당 함수가 실행 된 후 해당 객체를 사용할 수 있습니까? std::move의 경우 정의되지 않은 동작 이라는 것을 알고 있습니다.
iammilind

1
에 대해서 move: stackoverflow.com/a/7028318/576911 를 들어 forward, 당신은 좌변에 전달하는 경우가 좌변을받는 것처럼, 당신의 API가 반응한다. 일반적으로 이는 값이 수정되지 않음을 의미합니다. 그러나 그것이 상수가 아닌 lvalue이면 API가 수정했을 수 있습니다. rvalue를 전달하면 일반적으로 API에서 API가 이동했을 수 있으므로 stackoverflow.com/a/7028318/576911 이 적용됩니다.
Howard Hinnant

21

std::forward함수에 전달 된 방식대로 매개 변수 를 전달 하는 데 사용됩니다 . 여기에 표시된 것처럼 :

언제 std :: forward를 사용하여 인수를 전달합니까?

사용 std::move,를 rvalue로 이벤트를 객체 것은 아마도 이동 생성자 또는 우변을 받아들이는 기능을 개발하였습니다. 그것은을위한 것이 않는 std::move(x)경우에도이 x그 자체에 의해를 rvalue 없습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.