2017-03-14 3 views
3

나는 C++ 초보자이며 완벽한 전달이 std::move과 함께 어떻게 작동하는지 알고 싶습니다.완벽한 전달 및이 동작 내에서의 동작 이동 :

fillWithData 템플릿 함수를 사용하여 채울 std::vector<QueueData> queue()을 정의합니다. 완벽한 포워딩을 공부하는 데 시간을 할애했기 때문에 먼저이 컨텍스트에서 move 동작이 무엇인지 알아 내기 위해 올바르게 이해했는지 확인해야합니다.

fillWithDataforward 덕분에 접힌 규칙을 통해 lvalue 또는 rvalue로 매개 변수를 처리 할 수있는 가변 템플릿 함수입니다. (Q1 -이 맞습니까?)

template< class Container, typename ... Args > 
static void fillWithData(Container & oDataContainer, 
         Args&& ... args) // universal reference 
{ 
    typedef typename Container::value_type::element_type QueueDataPtr; 
    oDataContainer.emplace_back(std::forward<Args>(args)...); 
} 

이제 fillWithData에 전달할 인수를 취할에서 개체 User usr가 상상 :

내가 호출하면 fillWithData(queue, usr.getName(), usr.getEmail(), usr.getAddr())emplace 다음을 수행합니다은 전화?

  • 임시 QueueData 객체의 생성자.
  • 벡터 내부에 실제로 할당 된 객체의 생성자 (임시로 정의 된 경우 생성자, 그렇지 않으면 복사 생성자)를 이동합니다.
  • 임시 용 소멸자.

나는를 rvalue로 좌변을 처리 할 move의 장점이 걸릴 수 최적화하려면 (Q2 - 좌변 usr.getName()이다?) :

fillWithData(queue, std::move(usr.getName()), std::move(usr.getEmail()), std::move(usr.getAddr())) 이런 식으로

, (Q3)은 User 생성자로 직접 전달되는 값이며 벡터 내부에 직접 생성 된 새로운 객체입니까? 예를 들어, 난 그냥 fillWithData에 대한 호출 후 usr.getName()에 새 통화를 할 경우

또한 (Q4)는 데이터를 계속 사용할 수 있습니까? (나는 런타임 오류가있을 것 같아요).

마지막으로 (Q5) std::move이 없으면 완벽한 전달을 구현하는 것이 합리적입니까?

감사합니다.

+2

한 질문, 제발 엄지 손가락의 간단한 규칙이있다. 다섯이 아닙니다. –

답변

3

std::move은 완벽한 전달을 수행하지 않습니다. l 값 참조를 r 값 참조로 변환합니다. 캐스트를 수행했기 때문에 입력이 출력과 다릅니다. 따라서 완벽하지는 않습니다.

std::forward<X>은 완벽한 전달을 수행하지만 X의 유형이 추론되고 있어야합니다. 즉, 현재 함수의 템플릿 인수이며 범용 참조입니다.

겉으로보기에는 r 값 참조 변수 이름에서 std::move을 호출해야하는 이유가 있습니다.

또는 2로 선언되었는지 여부에 관계없이 이름이있는 변수는 실제로 l 값인이기 때문에 입니다.

그럼

int&& x = y();는 오직 r 값에 바인딩 L 자 값은 (Y는 r 값 기준 또는 임시을 반환 함).

int& x = y(); 또한 L 값이지만, (Y 중 하나의 int & 또는 INT & &을 반환 할 수있다)은 L 값이나 r 값 중 하나에 결합된다.

위의 경우 std::move(x)은 r 값 참조를 반환합니다. 첫 번째 경우에는 (겉으로보기에는) 완벽 할 것이며, 두 번째 경우에는 캐스팅되었을 것입니다. 따라서 완벽하게 전달되지는 않았습니다.

std::forward<>은 차이를 감지하지만 std::move는 차이를 감지합니다. 추정되는 상황에 요약

, , std::move가 항상 r 값의 참조를 반환하는 반면 std::forward<T>(x)는 동일한 카테고리 함수의 인수에 전달되었을 때의 X (1- valuenes 또는 R-valueness)를 반환 심지어 l 값 참조를 전달한 경우에도 마찬가지입니다.

? 을 감안할 때

: 다음

template<class T> void bar(T x); // pass by value 

: 질문 당

template<class Deduced> void foo(Deduced&& x) 
{ 
    // x is a universal reference in deduced context, 
    // so we probably want to forward it. 
    bar(std::forward<Deduced>(x)); 
} 

void foo(Known&& x) 
{ 
    // x is definitely an r-value reference. No point forwarding something 
    // we already know the category of - move it. 
    bar(std::move(x)); 
} 

void foo(Known x) 
{ 
    // x is definitely an l-value. No point forwarding an l-value 
    // reference, as this will cause an un-necessary copy. 
    // So we must cast x. 
    bar(std::move(x)); 
} 

void foo(Known const& x) 
{ 
    // x is definitely a const l-value reference. No point forwarding 
    // a const reference, and no point moving it, since a 
    // (Known const &&) is not useful. 
    // Whatever we do, there's going to be a copy. 
    bar(x); 
}