2013-04-05 2 views
2

:기본를 rvalue 방법 반환

std::string StringTest() 
{ 
    std::string hello_world("Testing..."); 

    return std::move(hello_world); 
} 

어떻게 출력 사용해야합니다

옵션 A :

auto& string_test_output=StringTest(); 

옵션 B :

auto string_test_output=StringTest(); 

StringTest()는 임시 값입니까? 그렇다면 옵션 A는 안전하지 않습니다. 일시적인 가치가 아니라면 옵션 B가 사본을 만들 것이라고 생각합니다.

RValue 참조에 익숙해지기 때문에 복사가 필요 없거나 불필요한 복사를 원하지 않으므로 값으로 반환하는 것은 여전히 ​​매우 위험합니다!

+1

값으로 돌아 오는 것을 두려워하지 마십시오. 모든 컴파일러는 NVRO를 사용하여 callsite에서 문자열을 생성합니다. – chris

+1

옵션 A는 옵션이 아닙니다. 컴파일 오류가 발생합니다. –

+0

@VaughnCato 반드시 그렇지는 않습니다. 컴파일되지만 std :: move는 거의 영향을 미치지 않습니다. – Agentlien

답변

3

는이 당신의 방법을 변경하는 것입니다 가장 좋은 방법 :

반환 된 객체가를 rvalue해야하는 기능을 말할 필요가 없습니다
std::string StringTest() 
{ 
    std::string hello_world("Testing..."); 

    return hello_world; 
} 

, 이것은 값의 존재에서 자동으로 제공 일시적입니다. 즉, 호출 사이트에서 어떤 이름에도 구속되지 않습니다. 따라서 초기화 된 유언 값은 수동으로 그러한 의도를 표현할 필요없이 (함수 내부의 임시가 완전히 생략되지 않는 한) 이동 구성되어 있습니다.

또한 반환 유형이 std::string이므로 rvalue-reference가 아닌 값으로 반환하므로 반환하기 전에 반환 인수를 이동해야합니다. 실제로 std::move을 호출하면 값을 반환하기 전에 불필요한 이동 생성자를 수행하도록 컴파일러를 속이는 것 외에는 아무런 효과가 없습니다. 이러한 트릭은 코드를 약간 더 복잡하게 만들거나 실행 속도를 늦추는 것 이외의 용도로 사용되지 않습니다.

값으로 돌아가고 싶습니까? 한 가지 이유는 Return Value Optimization (RVO)입니다. 대부분의 컴파일러는 이것을 수행합니다. 즉, 영리 해지기 위해 노력하고 참조를 반환하는 것보다 더 쉽게 벗어난 "복사본"을 반환하는 것이 좋습니다.

RVO를 적용 할 수없는 경우에도 rvalue-reference로 반환하면 여전히 반환되는 방식이 변경되지 않습니다. 값이 반환되면 호출 사이트에서 임시이므로 반환 값은 이미 rvalue로 전달할 수있는 rvalue가 될 것입니다. rvalue 참조는 인수로 필요한 모든 함수에 전달됩니다. 예를 들어 반환 값을 사용하여 변수를 초기화하고 반환 값이 생략되지 않으면 사용 가능한 경우 이동 생성자가 여전히 호출됩니다. 따라서 단순한 가치로 돌아가는 것만으로도 그다지 손실되지 않습니다.

이를 감안할 때, 당신은 아마 값을 잡기 위해 다음 중 하나를 수행해야합니다 값에 따라서 새로운 객체를 초기화

auto string_test_output = StringTest(); 
std::string string_test_output = StringTest(); 
+0

을 계속 사용합니다. RVO를 알고 있었지만 컴파일러가 rvalue라는 것을 알기 위해 여전히 std :: move (hello_world)를 안전한쪽에 추가해야합니다. 참고? – Grapes

+0

@ 포도주 아니요, 확실히 아닙니다. 그건 아무것도 추가하지 않습니다. 그것이 rvalue라는 사실은 호출 사이트에서 일시적인 것으로부터옵니다. 즉, 함수가 작성된 함수에서 리턴되며 함수가 종료 될 때 이름에 바인드되지 않습니다. 리턴하기 전에 함수 내부에서 rvalue를 사용하면 리턴되기 전에 불필요한 이동 생성자가 호출 될 위험이 있습니다. – Agentlien

+0

나는 std :: move가없는 것에 대한 당신의 추론을 완전히 이해합니다. 즉, 내가 RVO를 신뢰해서는 안되며 대신 std :: move를 사용해야하는 경우가 있습니까? – Grapes

0

성병 : : 문자열을 반환 (그리고 일반적으로, 어떤 이동 유형) 것 복사 구성을 실행하지 마십시오. 최악의 경우 이동 구성을 트리거하지만 일반적으로 복사 제거로 인해 런타임 오버 헤드가 발생하지 않습니다.

가치 의미 체계 및 비용에 대해서는 this article을 권장합니다.