2017-11-15 20 views
3

다음 최소 작업 예제는 옵션 1 또는 옵션 2의 코드를 사용할 때 컴파일되지만 옵션 3의 코드를 사용하면 이 아닌이 컴파일됩니다. emplace_back()move 생성자를 암묵적으로 사용/호출한다는 가정하에 명시적인 move()이 필요한 이유는 무엇입니까? r-valuel-value과 관련이 있습니까? 또는 소유권을 이전해야하는 std::unique_ptr과 관련이 있습니까? (특히이 컨셉을 처음 접했을 때입니다.)이 예제에서 emplace_back으로 이동이 필요한 이유는 무엇입니까?

move()을 호출하지 않으면 push_back()의 옵션 4도 컴파일되지 않습니다.

#include <iostream> 
#include <vector> 
#include <memory> 

class Beta { 
public: 
    Beta(int x, int y, int z): mX(x), mY(y), mZ(z) { }; 
    int mX; int mY; int mZ; 

}; 

class Alpha { 
public: 
    std::vector<std::unique_ptr<Beta>> betaVec; 
    void addBeta(int x, int y, int z) { 
     // only choose one of the following options: 
     // option 1 (compiles) 
     std::unique_ptr<Beta> pBeta = std::make_unique<Beta>(x, y, z); 
     betaVec.emplace_back(move(pBeta)); 

     // option 2 (compiles) 
     betaVec.emplace_back(std::make_unique<Beta>(x, y, z)); 

     // option 3 (does not compile) 
     std::unique_ptr<Beta> pBeta = std::make_unique<Beta>(x, y, z); 
     betaVec.emplace_back(pBeta); 

     // option 4 (does not compile) 
     std::unique_ptr<Beta> pBeta = std::make_unique<Beta>(x, y, z); 
     betaVec.push_back(pBeta); 

     // option 5 (compiles) 
     std::unique_ptr<Beta> pBeta = std::make_unique<Beta>(x, y, z); 
     betaVec.push_back(move(pBeta)); 
    } 
}; 

int main() { 

    return 0; 
} 

참고 : 나는이 링크 된 질문에 대한 답변이 유용하다하더라도, 기능에 unique_ptr 매개 변수를 전달하는 방법에 대한 this question의 중복이라고 생각하지 않는다,이 같은 정의에 대한 요구하고있다 unique_ptr내에서 함수를 호출 한 다음 함수를 끝내면서 파괴되지 않도록 vector 멤버로 이동하고이 컨텍스트에서 emplace_back()을 구체적으로 묻습니다.

또한이 컨텍스트에서 설명을 번역하는 것이 때때로 어렵 기 때문에이 컨텍스트에서 설명하는 것이 유용 할 것이라고 생각합니다. 고맙습니다!

+0

나중에 참조 할 수 있도록 유용하고 관련있는 질문입니다. https://stackoverflow.com/questions/29089227/push-back-or-emplacle-back-with-stdmake-unique 및 https://stackoverflow.com/ 질문/35404932/stdvectoremplace-back-and-stdmove. – PhysicsCodingEnthusiast

답변

2

나는 emplace_back() 암시 /은 이동 생성자에게

죄송를 호출을 사용한다는 가정하에,하지만 넌 가정은 잘못된 것입니다. emplace_back은 벡터에서 개체를 즉석에서 구성합니다. 즉, 매개 변수에서 개체를 복사/이동하는 대신 복사/이동 생성자를 피하는 요소를 직접 생성합니다.

이제 동일한 (그러나 다른) 객체로 객체를 구성하면 물론 복사 또는 이동 생성자가 대신 사용됩니다. 이는 사용자의 경우에 발생합니다. 당신이 std::unique_ptr을 복사 할 수 없기 때문에

는 왜 필요 명시 적 move()

입니다.

new (place) T(std::forward<Ts>(args)...); 

그것은 당신이 한 경우처럼 : T a(std::forward<Ts>(args)...) (건설 만, 실제로 같은 일을하지 않습니다) 기본적으로, emplace_back이 유사한 무언가를.

는 이제 좀 더 분명 있습니다

T option1(std::move(pBeta)); // ok, move 
T option3(pBeta); // error, copy 

그것은 r-valuel-value 함께 할 수있는 뭔가가 있나요? 또는 소유권을 이전해야하는 std::unique_ptr과 관련이 있습니까?

음, 그렇습니다.std::unique_ptr은 소유권을 명시 적으로 전송해야하기 때문에 복사본이 사용 중지되고 이전이 불가능합니다 (여전히 소유권을 이전하려고합니다! 복사는 어디에서나 발생할 수 있습니다 - 이유는 std::auto_ptr가 삭제 된 다음 삭제 된 이유입니다). rvalue는 기본적으로 이동 의미를 사용하지만 lvalue는 이동 의미를 사용하지 않습니다. std::move을 사용하면 lvalue에서 prvalue 로의 변환을 수행하므로 lvalue가 있다는 사실을 효과적으로 숨기고 컴파일러는 행복하게 그것을 옮길 것입니다.

+0

답장을 보내 주셔서 감사합니다. 나는 후속 질문이 있는지 신중하게 검토 할 것이지만, 지금은 매우 빠르고 멍청한 질문이 있습니다. 코드에서, 왜 내가 단순히'move()'를 호출 할 수 있었을 까? 'std :: move()'? 나는'namespace std'를 사용하지 않으며'std'의 다른 모든 기호는'std ::'접두어를 올바르게 요구합니다 ... – PhysicsCodingEnthusiast

+1

@PhysicsCodingEnthusiast 그건 바보 같은 질문이 아닙니다! 'pBeta'가 네임 스페이스에 있기 때문입니다. 컴파일러는 함수의 인수의 네임 스페이스를 검색하여 찾을 수 있습니다. 이를 ADL이라고합니다. – Rakete1111

+0

아, 알겠습니다. 그건 의미가 있습니다. 고맙습니다. ADL이 적용될지라도'std ::'를 포함하는 것이 안전 할 것입니다. 또한, 혼란의 또 하나의 요점 :이 예에서 소유권의 이전은 무엇입니까? 'addBeta' 함수와 * betaBec' 함수에서 온 것입니까? – PhysicsCodingEnthusiast