2017-01-28 7 views
-2
Foo(Foo&& other) { 
    this->bar = other.bar; 
    other.bar = nullptr; 
} 

Foo(Foo* other) { 
    this->bar = other->bar; 
    other->bar = nullptr; 
} 

위의 두 개는 똑같은 것으로 보입니다. 그렇다면 왜 이동 생성자를 사용하는 것이 좋습니다? 그것이 제공하는 이점은 무엇입니까? 적절한 이동 생성자를 사용이동 생성자와 포인터를 전달하는 장점은 무엇입니까?

+2

글쎄요, 처음에는 rvalue의 주소를 가져올 수 없습니다. – Brian

+2

장점은 해당 이동/복사 컨텍스트에서 이동 생성자가 자동으로 사용된다는 것입니다. 귀하의 "포인터"생성자되지 않습니다. – AnT

+0

또한 참조는 null이 될 수 없지만 포인터가 될 수 있으므로 스와핑 전에 해당 조건을 명시 적으로 확인해야합니다. –

답변

4

이유는 많다 :

  1. 대회. 다음 코드를 고려하십시오 : 당신이 그 코드를 볼 경우

    Foo foo; 
    Foo bar(std::move(foo)); 
    

    , 그것은 이다 풍부 당신이 뭘 하려는지 명확 : 당신이 barfoo 이동하고 있습니다. 대조적으로 :

    이것은 무엇을 의미합니까? 다른 Foo에 대한 포인터를 저장하고 있습니까? Foo 어떤 종류의 연결된 목록 노드 유형입니까? 당신은 Foo의 포인터 기반 생성자에 대한 설명서에서 찾아야 할 것입니다.

  2. prvalues에 대한 포인터를 가져올 수 없습니다. Foo bar(Foo{}) (pre-C++ 17)은 임시로 prvalue를 생성 한 다음 bar으로 이동할 수 있습니다 (이동은 pre-C++ 17에서 생략 할 수 있습니다). 그러나 당신은 이것을 할 수 없습니다 : Foo bar(&Foo{}).

  3. 의미가있는 것으로부터 자동으로 이동합니다. C++ 17의 일반화 생략이 자동 이동의 대부분은 멀리 갈 수 있지만, 남아 몇 가지가있다 :이 std::move를 호출 할 필요없이 foo에서 이동합니다

    Foo function() 
    { 
        Foo foo; 
        //Do stuff 
        return foo; 
    } 
    

    . 그 이유는 foo이 파괴 될 지역 변수이기 때문입니다. 이 방법으로 반환하면 반환 값으로 옮기는 것이 매우 합리적이라는 것을 의미합니다.

    길을 명시 적으로 작성하려면 return &foo이 필요합니다. 그리고 그것은 auto 반환 유형 공제로 일을 다소 어렵게 만듭니다. 이러한 함수는 Foo*을 추론합니다. 즉, 방금 포인터가 매달려있는 것을 반환합니다. 반면에 return foo;을 수행하면 Foo prvalue가 자동 이동 (생략 될 수 있음)으로 추정됩니다.

  4. nullptr 검사 필요 없음. Foo*을 사용하면 누군가가 null 포인터를 전달할 가능성이 있습니다. 참조가있는 반면, 그것은 훨씬 더 어려울 것입니다 (그리고 그들은 이미 UB를 호출했을 것입니다). 우리는 기존의 언어 구조와 지원을 이동하고자한다면

, 우리는 그냥 "이동"이 아닌 포인터를 의미하는 비 const 참조를 사용했을 것입니다. 자체 구문을 제공함으로써, 우리가 무언가를 움직이고있을 때와 그렇지 않을 때를 분명히합니다.