2017-01-14 4 views
2

다음 코드 한 : 내가 컴파일C++ 함수가 벡터 <shared_ptr<>>을 반환하면 어떻게됩니까?

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

class Test 
{ 
public: 
    Test() {} 
    ~Test() { std::cerr << "Delete\n"; } 
}; 

std::vector<std::shared_ptr<Test>> makeList() 
{ 
    std::vector<std::shared_ptr<Test>> list; 
    list.push_back(std::make_shared<Test>(Test())); 

    return std::move(list); 
} 

int main(int argc ,char **argv) 
{ 

    std::vector<std::shared_ptr<Test>> list; 
    std::cerr << "Before\n"; 
    list = makeList(); 
    std::cerr << "After\n"; 

    return 0; 
} 

:

clang++ -std=c++14 -o ptr ptr.cpp 

출력은 다음과 같습니다

Before 
Delete 
After 
Delete 

내 질문은 : 객체가 거기 삭제하는 이유 makeList의 기능은 무엇입니까? 내 가정은 list 함수에서 listmain로 이동 될 것입니다 따라서 아무 개체가 삭제됩니다/프로세스에서 재현?

피할 수 있습니까? (분명히이 코드는 최적이 아닙니다)?

+6

'Test()'를 사용하여 임시'Test' 개체를 만듭니다. 그 복사본이'make_shared'에 의해 만들어지면 임시 파일이 파괴됩니다. 효율을 위해'std :: make_shared ()' –

+5

'return std :: move (list);'는'return list;'이어야한다. –

+0

^^ This. OP : 당신의 컴파일러가 이것에 대해 경고하지 않는다면, 아마도 더 나은 컴파일러를 얻거나 (또는 ​​경고를 켜는) 시간을 갖을 것입니다.'std :: move()'는 리턴 값 최적화를 금지한다. clang의 최신 버전에서 이에 대해 경고 할 수 있습니다. – marko

답변

4

2 명 변경 :

std::vector<std::shared_ptr<Test>> makeList() 
{ 
    std::vector<std::shared_ptr<Test>> list; 

    // make_shared does not need a copy of an object, just constructor arguments 
    list.push_back(std::make_shared<Test>()); 

    // return std::move(list) will defeat RVO. Never do that.  
    return list; 
} 

그래서, 중요한 부분은 다음과 같습니다

list.push_back(std::make_shared<Test>(Test())); 

->

list.push_back(std::make_shared<Test>()); 

오늘도 똑같이 보았 기 때문에 명확히하기 위해 차이점을 보는데 어려움이있었습니다.

+0

Ok, 고맙다, 나는 그것이 차이를 만들 것이라고 강요했기 때문에 나는 단지 움직임을 시험해 보았다. 그러나 나는 두 가지 옵션을 시도했다. 그래서 현실은 문제는 내가 make_shared를 호출 할 때 temp 객체를 생성한다는 사실에서 나온다. 고마워. – user18490

3
list.push_back(std::make_shared<Test>(Test())); 

여기서 임시는 Test()으로 생성됩니다. 그런 다음 Test에 대한 복사기가 호출되고 임시 파일이 삭제됩니다. 첫 번째 소멸자 호출입니다.

list이 소멸되면 두 번째 소멸자 호출이 프로그램 끝 부분에 나타납니다. 일시적으로 생성을 방지하기

올바른 형식은 다음과 같습니다

list.push_back(std::make_shared<Test>()); 

당신이 값을 반환 std::move를 사용하지 말아야 외에도 컴파일러는 이러한 경우에 반환 값 최적화을 적용 할 수 있기 때문이다.

2

라인 list.push_back(std::make_shared<Test>(Test())); 임시 Test하게하고 std::make_shared<T>으로 구성된 실제 Test로 이동시킨다. 이 임시는 그 때 파괴된다.

std::make_shared<T>은 구성시 인수가 T이어야합니다. 생성 된 기본값이 T이면 인수를 제공하지 마십시오.

올바른 사용은이 경우에, 이것이다 :

list.push_back(std::make_shared<Test>());