2013-07-31 2 views
2

통과하여 I는 다음과 같은 기능을 가지고변형에 의한 전달에 기준 복귀

void read_int(std::vector<int> &myVector) 

나 그것을 기준으로 myVector을 채울 수있다. 그것은 다음과 같이 사용됩니다

std::vector<int> myVector; 
read_int(myVector); 

나는 결국이이에 약간에게 코드를 (원래의 기능을 유지) 리팩토링 할 :

auto myVector = read_int(); // auto is std::vector<int> 

달성하기 위해 최선의 중간 기능을 것입니다 무엇 이?


그것은 다음과 같은 솔직 대답은 최적 것을 나에게 보인다

내가 생각
std::vector<int> read_int() { 
    std::vector<int> myVector_temp; 
    read_int(myVector_temp); 
    return myVector_temp; 
} 
+6

그리고 왜 이것이 차선책이라고 생각합니까? – delnan

+0

새로운 함수가 중간 벡터'벡터 '을 생성하지 않을까요? 그럼 선언에 복사 될까요? –

+2

원본 버전보다 훨씬 뛰어난 버전입니다. 실적이 걱정된다면 [반환 값 최적화] (http://en.wikipedia.org/wiki/Return_value_optimization)를 읽어보십시오. – juanchopanza

답변

3

명백한 대답은 정확하고 기본적으로 최적입니다. 에서

void do_stufF(std::vector<int>& on_this); // (1) 
std::vector<int> do_stuff_better() {   // (2) 
    std::vector<int> myVector_temp;   // (3) 
    do_stuff(myVector_temp);     // (4) 
    return myVector_temp;     // (5) 
} 

(3) 우리 (스택)에 자동 저장 명명 된 결과 값을 생성한다.

(5) 우리는 함수에서 이름 지정된 반환 값만 반환하며 함수의 다른 곳에서는 반환 값을 반환하지 않습니다. (3)과(5) 컴파일러가 myVector_temp 물체의 존재를 생략하다 (거의 확실하고)가 허용되기 때문에

. 함수의 반환 값을 직접 생성하고 myVector_temp이라고합니다. 기존의 이동 또는 복사 생성자가 필요하지만 여전히 호출하지 않습니다. do_stuff_better를 호출 할 때

다른 쪽 끝에서

, 어떤 컴파일러는 호출에서 할당을 제거하다 할 수 있습니다

컴파일러 효과적으로 "밥 포인터의"를 전달하고 그것의 반환을 구성 do_stuff_better()에게 허용
std::vector<int> bob = do_stuff_better();  // (6) 

값을 bob의 위치에 추가하여이 사본 구성을 제거하십시오. do_stuff_better()이 반환 값을 생성하도록 요청 된 위치가 bob의 위치와 같아 지도록 호출이 이루어지는 방식을 조정할 수 있습니다.

그리고 C++ 11에서는 두 엘레멘트에 대한 요구 사항이 모두 충족되지 않거나 컴파일러에서 사용하지 않기로 선택한 경우에도 copy 대신 move을 사용해야합니다.

라인 (5) 우리는 지역적으로 선언 된 자동 저장 기간 변수를 평범하고 간단한 return 문으로 반환합니다. 이렇게하지 않으면 반환 값이 암시 적 move이됩니다.

줄에서 (6)이 함수는 이름이없는 개체 인 rvalue를 반환합니다. bob이 구성되면 move - 구성됩니다.

move ing a std::vector은 ~ 3 포인터의 값을 복사 한 다음, vector의 크기에 관계없이 원본을 제로로 구성합니다. 요소를 복사하거나 이동할 필요가 없습니다.

우리가 do_stuff_better() 내에서 명명 된 지역 변수를 제거하고 우리가 do_stuff_better()return 값을 제거하고 대신 직접 bob를 구성 위 elisions, 모두 다소 취약하다. 컴파일러가 그러한 엘레멘트를 할 수있는 규칙을 배우고, 컴파일러가 실제로 엘리트를 수행하는 상황을 배우는 것도 가치가 있습니다.

오류 상태를 확인한 후 do_stuff_better()return std::vector<int>()을 수행 한 지점이있는 경우 취약한 방법의 예로서 기능 중 일부가 차단되었을 수 있습니다.

elision이 차단되거나 컴파일러가 사례를 구현하지 않더라도 컨테이너가 move '이라는 사실은 런타임 비용이 최소화된다는 것을 의미합니다.

1

, 당신은 구글 쿼리에 더 약 move semantics (링크를 읽을 수 있고, 논문의 많은에게있다 이것에 - 다만 1 개를 선택하십시오).

간략히 말하자면 C++에서 모든 STL 컨테이너는 함수에서 반환되므로 반환되는 값 (소위 오른쪽 참조라고 함)에서 해당 변수를 할당 할 변수로 이동하게됩니다. . 실제로는 데이터 대신 std :: vector의 일부 필드 만 복사합니다. 그 내용을 복사하는 것보다 훨씬 빠릅니다.

+0

복사가 생략되지 않은 경우에만 발생합니다. 그리고 elion은 C++ 03에서도 작동합니다. :) – juanchopanza

+0

@juanchopanza 물론, 질문은 C++ 11로 태그되었습니다. 그럼에도 불구하고 실제로 주목할만한 사실입니다. – Spook