2012-01-26 3 views
54

여기는 pimpl에 대해 unique_ptr을 사용하려고 시도하는 것을 단순화 한 것입니다. 나는 클래스가 정말로 포인터를 소유하기를 원하기 때문에 unique_ptr을 선택했다 - 나는 pimpl 포인터와 클래스의 수명을 같게하고 싶다. 여기pimpl에 unique_ptr을 어떻게 사용합니까?

#ifndef HELP 
#define HELP 1 

#include <memory> 

class Help 
{ 

public: 

    Help(int ii); 
    ~Help() = default; 

private: 

    class Impl; 
    std::unique_ptr<Impl> _M_impl; 
}; 

#endif // HELP 

소스입니다 :

#include "Help.h" 

class Help::Impl 
{ 
public: 
    Impl(int ii) 
    : _M_i{ii} 
    { } 

private: 

    int _M_i; 
}; 

Help::Help(int ii) 
: _M_impl{new Help::Impl{ii}} 
{ } 

내가 잘 라이브러리로이 컴파일 할 수

어쨌든, 여기 헤더입니다. 제가 테스트 프로그램에서 사용하려고 할 때하지만 이것은 잘 알려진 safety feature입니다

[email protected]:~/ext_distribution$ ../bin/bin/g++ -std=c++0x -o test_help test_help.cpp Help.cpp 
In file included from /home/ed/bin/lib/gcc/x86_64-unknown-linux-gnu/4.7.0/../../../../include/c++/4.7.0/memory:86:0, 
       from Help.h:4, 
       from test_help.cpp:3: 
/home/ed/bin/lib/gcc/x86_64-unknown-linux-gnu/4.7.0/../../../../include/c++/4.7.0/bits/unique_ptr.h: In instantiation of 'void std::default_delete<_Tp>::operator()(_Tp*) const [with _Tp = Help::Impl]': 
/home/ed/bin/lib/gcc/x86_64-unknown-linux-gnu/4.7.0/../../../../include/c++/4.7.0/bits/unique_ptr.h:245:4: required from 'void std::unique_ptr<_Tp, _Dp>::reset(std::unique_ptr<_Tp, _Dp>::pointer) [with _Tp = Help::Impl; _Dp = std::default_delete<Help::Impl>; std::unique_ptr<_Tp, _Dp>::pointer = Help::Impl*]' 
/home/ed/bin/lib/gcc/x86_64-unknown-linux-gnu/4.7.0/../../../../include/c++/4.7.0/bits/unique_ptr.h:169:32: required from 'std::unique_ptr<_Tp, _Dp>::~unique_ptr() [with _Tp = Help::Impl; _Dp = std::default_delete<Help::Impl>]' 
Help.h:6:7: required from here 
/home/ed/bin/lib/gcc/x86_64-unknown-linux-gnu/4.7.0/../../../../include/c++/4.7.0/bits/unique_ptr.h:63:14: error: invalid application of 'sizeof' to incomplete type 'Help::Impl' 

얻을. 나는 따라하려고 노력했다.

제 문제는 헤더에 Help :: Impl 선언을 넣으면 pimpl의 이점을 없애는 것 같습니다. 클래스 레이아웃은 사용자에게 표시됩니다. 정의는 숨겨져 있지만 도움말 클래스와 비공개 멤버로 할 수 있습니다. 또한 Impl의 선언을 포함하여 내가 별도로 유지하기를 좋아할만한 새로운 헤더를 가져온다.

무엇이 누락 되었습니까? 여러분은 Impl 선언에 무엇을 넣었습니까? 내가 잘못된 dtor을하고 있습니까? 아!

+2

[GotW # 101 : 컴파일 방화벽, 파트 2] (http://herbsutter.com/gotw/_101/) 및 [이 관련 질문] (http://stackoverflow.com/q/8595471)/636019). – ildjarn

+1

낡은 질문이지만, 'unique_ptr'로 구현 된 PImpl은 (cppreference (http://en.cppreference.com/w/cpp/language/pimpl)에서 설명했듯이) 완전한 정확성을 위해 ['propagate_const'] (http://en.cppreference.com/w/cpp/experimental/propagate_const)와 같은 것으로 싸여 져야합니다. – jdehesa

+1

@jdehesa 고맙습니다. 일부 API 어색함에 대한 해결책으로 propagate_const를 찾고있었습니다. unique_ptr이 기본적으로이 의미에서 손상되었는지 거의 궁금합니다. 그것은 propagate_const가 내장되어 있거나 적어도 디폴트가되어야하는 것 같습니다. – emsr

답변

69

나는 당신의 test_help.cpp가 실제로 당신이 디폴트로 선언 한 ~Help() 소멸자를 본 것으로 믿는다. 그 소멸자에서 컴파일러는 unique_ptr 소멸자도 생성하려고 시도하지만 그것에 대해서는 Impl 선언이 필요합니다.

그래서 소멸자 정의를 Help.cpp로 이동하면이 문제는 없어야합니다.

- 편집 - 당신은 역시 CPP 파일에서 기본값으로 소멸자를 정의 할 수 있습니다 :

Help::~Help() = default; 
+9

좋아요, 헤더에서 저는 헬퍼에 대한 dtor를 * 선언했습니다. 그렇다면 구현 파일에서 Help :: ~ Help() = default; Woot !!! 감사. 모든 것이 작동합니다! – emsr

+0

우수함 –

+4

'unique_ptr'을 포함한 스마트 포인터는 불완전한 유형으로 작업해야합니다. "Deleter"함수는 생성시 할당되므로 포인터 사용자는 삭제 방법을 알 필요가 없습니다. 이 방법으로 문제가 해결되면 그의 'unique_ptr' 구현이 깨졌습니다. –

1

참고이 unique_ptr 정의에서 :

표준 :: unique_ptr pImpl 관용구에서 핸들로서의 사용을 용이하게하는 것과 같이 불완전한 유형 T에 대해 구성 될 수있다. 기본 Deleter가 사용되는 경우, Deleter가 호출되는 코드의 위치에서 T가 완료되어야합니다.이 작업은 destd :: unique_ptr의 소멸자, 이동 대입 연산자 및 재설정 멤버 함수에서 발생합니다.

관련 문제