2013-08-26 3 views
4

개별 배열에 데이터를 저장하는 사용자 정의 컨테이너 Container을 만들고 싶습니다. 그러나 컨테이너에 대한 반복 작업을 쉽게하기 위해 컨테이너에 'operator[]'을 오버로드하여 '보기'를 제공하고 모든 컨테이너 변수를 실제 컨테이너에 대한 참조로 유지하는 단일 구조체 Value을 반환합니다. 위의 코드는 지금까지 내가 말할 수있는 노력하고 있습니다,하지만 난 궁금하네요C++에서 rvalue 참조를 사용하여 불필요한 인스턴스를 피하는 방법

#include <iostream> 
using namespace std; 

struct Value { 
    Value(int& data) : data_(data) { } 
    int& data() { return data_; } 
    int& data_; 
}; 

struct Container { 
    Value makeValue(int i) { return Value(data_[i]); } // EDIT 1 
    Value&& operator[](int i) { 
    // return std::forward<Value>(Value(data_[i])); 
    return std::forward<Value>(makeValue(i)); // EDIT 1 
    } 

    int data_[5] = {1, 2, 3, 4, 5}; 
}; 

int main(int, char**) 
{ 
    // Create and output temporary 
    Container c; 
    cout << c[2].data() << endl; // Output: 3 - OK! 

    // Create, modify and output copy 
    Value v = c[2]; 
    cout << v.data() << endl; // Output: 3 - OK! 
    v.data() = 8; 
    cout << v.data() << endl; // Output: 8 - OK! 

    // Create and output reference 
    Value&& vv = c[2]; 
    cout << vv.data() << endl; // Output: 8 - OK, but weird: 
          // shouldn't this be a dangling reference? 
    cout << vv.data() << endl; // Output: 468319288 - Bad, but that's expected... 
} 

내가 여기에 가장 좋은 방법을 사용하는 경우 :

  1. 가이 올바른지 이것은 내가 지금까지 무엇을 가지고 있습니다 불필요한 복사를 피하려는 경우 Value을 가치 기준으로 되돌립니다.
  2. std::forward의 사용이 맞습니까? std::move을 사용해야합니까 (이 예에서는 모두 작동할까요)?
  3. 컴파일 된 프로그램의 출력이 주석에 설명되어 있습니다. Value&& vv...을 선언 할 때 (또는 심지어 구문 적으로 금지해도) 매달린 참조를 피할 수있는 방법이 있습니까? Value 인스턴스 직접 operator[]하지만 다른 방법에서 헬퍼 기능에 생성되지 않도록 1

EDIT I는 소스 코드에 작은 변화를 만들었다. 그게 아무것도 바꿀까요? 표시된대로 방법을 사용해야합니까, 아니면 여기에 std::move/std::forward을 사용해야합니까?

+0

http://stackoverflow.com/questions/1116641/is-returning-by-rvalue-reference-more- 効率과 비슷합니다. –

답변

3

필자는 불필요한 복사를 피하기 위해 값을 rvalue 참조로 반환하는 것이 맞습니까?

아니요 std::move 또는 std::forward과 같은 도우미가 아닌 값에서 참조 값을 반환하는 것은 잘못된 것입니다. 우세한 참조는 여전히 참조입니다. 임시 변수 또는 지역 변수에 대한 참조를 반환하는 것은 항상 잘못된 것이지 여전히 잘못된 것입니다. 이것들은 오래된 C++ 규칙과 같습니다.

std::forward의 사용이 맞습니까? std::move을 사용해야합니까 (이 예에서는 모두 작동할까요)?

이전 질문에 대한 대답은이 말을 근사하게 만듭니다.

컴파일 된 프로그램의 출력이 주석에 설명되어 있습니다. Value&& vv...을 선언 할 때 (또는 심지어 구문 적으로 금지해도) 매달린 참조를 피할 수있는 방법이 있습니까?

매달려있는 참조를 만드는 부분은 Value&& vv = c[2];이 아닙니다. 그것은 operator[] 자체입니다 : 첫 번째 질문에 대한 답변을보십시오.

이 경우 Rvalue references는 거의 변경되지 않습니다.당신은 항상했던 것처럼 그냥 일을 할 :

Value operator[](int i) { 
    return Value(data_[i]); 
} 

모든 컴파일러 가치가 사본 또는 이동 또는 아무것도하지 않고 반환 값의 직접 초기화에이 최적화됩니다 사용. 벙어리/쓸데없는/별난/실험 컴파일러로는 최악의 경우 움직일 것입니다 (그러나 왜 누군가는 심각한 것을 위해 그런 것을 사용합니까?).

따라서 Value v = c[2]; 라인은 v을 직접 초기화합니다. Value&& vv = c[2]; 줄은 임시 변수를 초기화하고이를 rvalue 참조 변수에 바인딩합니다. 이들은 const&과 동일한 속성을 가지며 임시 수명의 수명을 참조 수명까지 연장하므로 매달리지 않습니다.

요컨대 같은 오래된 C++이 항상 작동하며 정확하고 뛰어난 결과를 제공합니다. 그것을 잊지 마세요.

+0

방금 ​​소스 코드에서 예제를 약간 변경했습니다. 이 경우에도 마찬가지입니까? –

+0

차이점이 없습니다. op []는 여전히 임시 참조를 반환합니다. –

+0

좋아, 나는 그것을 이해했다고 생각한다. 불필요한 복사를 피하는 관점에서'makeValue (int i) '의 서명/정의가 이와 같이 정확합니까? 아니면 여기서 뭔가를 변경해야합니까? –

3

임시 개체에 대한 참조를 반환하는 것은 r 값 참조 인 경우에도 항상 잘못된 것입니다! 개체에 액세스 할 때까지 사라질 것입니다. 이 경우에는 불필요한 사본을 피하려면 일시적으로 반환하는 return 문 하나를 사용하십시오. 복사/이동 생략 복사되지 않는 개체 처리됩니다 :

Value operator[](int i) { 
    return Value(data_[i]); 
} 

복사/이동 생략 및 복사하지 않고/이동을 억제하는 기능을 통해 임시 객체를 전달 이동보다 더 적은 작업입니다.

+0

'value'의 인스턴스를'operator []'메소드에서 만들지 않고 다른 도우미 함수 (위의'makeValue (int i)'참조)에서 만들면 어떻게 될까요? –

+0

복사/이동 elision은 또한 return 문 체인을 따라 작동합니다. 당신의 버전은'std :: forward()'호출로 인해 복사/이동 엘레 비전을 금지하고 참조가 액세스되기 전에 파괴 된 객체에 대한 참조를 반환합니다. –

+0

이 경우'std :: forward (makeValue (i))'가 필요하다는 뜻입니까, 아니면 대신'makeValue (i)'를 쓸 수 있습니까? –

관련 문제