2016-09-30 3 views
13

std::unique_ptr class (소유권 이동을 시도하는) 멤버를 호출자에게 반환하려고합니다.클래스 메서드에서 unique_ptr을 반환하는 중

class A { 
public: 
    A() : p {new int{10}} {} 

    static std::unique_ptr<int> Foo(A &a) { 
    return a.p; // ERROR: Copy constructor getting invoked 
       // return std::move(a.p); WORKS FINE 
    } 

    std::unique_ptr<int> p; 
}; 

내가 컴파일러 (GCC-5.2.1) 생각 std::move()를 통해 명시 적 의도없이이 경우 반환 값 최적화 (복사 생략)를 할 수있을 것입니다 : 다음은 샘플 코드입니다. 하지만 그렇지 않습니다. 왜 안돼?

다음 코드 보인다, 잘 동작하는 것 동등한 :

std::unique_ptr<int> foo() { 
    std::unique_ptr<int> p {new int{10}}; 
    return p; 
} 
+2

위대한 첫 번째 질문입니다. StackOverflow에 오신 것을 환영합니다! – Barry

답변

11

[class.copy]의 규칙은 다음과 같습니다

[...] 때 표현return 문 본문에 자동 저장 기간이 선언 된 객체의 이름을 지정하는 ID 표현 ( 괄호 안의 문자) 또는 매개 변수 선언 가장 안쪽 함수를 포함하는 또는 람다 식, 과부하 해결 에 대한 복사 생성자 선택은 해당 개체가 rvalue로 지정된 것처럼 처음 수행됩니다. 이 예에서

:

std::unique_ptr<int> foo() { 
    std::unique_ptr<int> p {new int{10}}; 
    return p; 
} 

p 함수 본문에 선언 자동 저장 기간을 가진 오브젝트의 이름이다. 따라서 반환 값으로 복사하는 대신 먼저 이동을 시도합니다. 그건 잘 작동합니다.

그러나이 예에서는

: 적용되지 않습니다

static std::unique_ptr<int> Foo(A &a) { 
    return a.p; 
} 

. a.p은 객체의 이름이 아니므로 과부하 해결을 시도하는 것이 아니라 직설법 인 것처럼 정상적인 작업을 수행합니다. 복사를 시도합니다. 이것은 실패하므로 명시 적으로 move()해야합니다.


이는 규칙의 표현이지만 사용자의 질문에 대한 답변이되지 않을 수도 있습니다. 왜 이것이 규칙인가? 기본적으로 - 우리는 안전하려고 노력하고 있습니다. 지역 변수의 이름을 지정하는 경우 return 문에서 항상 변수로 이동하는 것이 안전합니다. 다시 액세스 할 수 없습니다. 쉬운 최적화, 가능한 단점. 그러나 원래 예제에서 a은이 함수가 소유하지 않으며 a.p도 아닙니다. 그것은 본질적으로 그것에서 옮기는 것이 안전하지 않기 때문에, 언어는 자동적으로 그것을하려고하지 않을 것입니다.

-1

a.p은 복사 할 수 없으므로은 std::unique_ptr이므로 복사 할 수 없습니다 (다른 이유로). 그리고 a.pA::Foo(A&)의 몸통을 넘어서기 때문에 컴파일러가 a.p에서 자동으로 이동하려고 시도하면 매우 놀랍습니다 (a의 클래스 불변성을 파괴 할 수 있음). 만약 당신이 return std::move(a.p);라면 작동하지만, 명시 적으로 a.p을 훔칩니다.

+0

복사 elision이 이동 전용 유형 (예 : OP의 두 번째 예)에 적용될 수 있습니다. – Barry

+0

@ 배리 OK, 내 첫 문장이 잘못되었습니다. 복사 제거는 이동에도 적용됩니다. 그러나, 나는 대답의 나머지가 아직도 서 있다고 믿는다. –

+0

@AndreKostur : 코더가 복사 생성자가 삭제 된 unique_ptr을 명시 적으로 반환하려고하기 때문에 유일한 옵션은 이동이 일어나고 복사가 제대로 작동해야합니다 (IMO). 실제로 나를 놀라게 한 것은 경고가 아니라 컴파일 오류였습니다. – axg

관련 문제