2016-07-21 2 views
1

저는 PIMPL 관용구를 사용하고 있습니다. 특히 this post에서 제공된 템플릿을 사용하고 있습니다. 아래 클래스의 집합을 감안할 때 VS2015 업데이트 3, 나는 오류 컴파일는군요 컴파일 (소스 파일 SRC ​​\ A.cpp를 컴파일) 정의되지 않은 형식 'C : C_impl'의PIMPL 관용구를 사용할 때 왜이 유형이 불완전합니까?

오류 C2027 사용을

오류 C2338은 불완전한 유형 (소스 파일 src \ A.cpp 컴파일)을 삭제할 수 없습니다.

경고 C4150 불완전한 유형 'C :: C_impl'에 대한 포인터 삭제. (소스 파일 SRC ​​\ A.cpp 컴파일)라는 더 소멸자

뭔가가 자동으로 생성되는 ~C()을 방지하고 있다고 생각하는 날 리드하지만, 내가 무엇을 이해하지 않는, C::~C() 주석을 해제하여이 문제를 해결할 수 있습니다. 다음 중 하나에 해당하는 경우 this reference에 따르면, 타입 T 소멸자 암시 삭제 같이 정의된다

  1. T 비 정적 데이터 (삭제되거나 액세스 소멸자) 파괴 할 수없는 부재를 구비
  2. T는 파괴 할 수없는 직접 또는 가상 기본 클래스가 있습니다 (삭제되거나 액세스 할 수없는 소멸자가 있음)
  3. T는 공용체가 아니며 변형자가 아닌 소멸자가있는 변형 멤버가 있습니다.
  4. 암시 적 선언 소멸자 가상이다 (연산자 (삭제) 삭제 모호하거나 액세스 함수에 대한 호출을 초래한다.
및 해제 기능을위한 룩업 (기본 클래스 가상 소멸자 때문에)

항목 # 2, 3, 분명히 4 C에 적용되지 않습니다, 나는 pimpl<> (C 's의 유일한 구성원)이 명시 적으로 소멸자를 정의하기 때문에 # 1이 적용된다고 생각하지 않는다.

하는 사람이 설명해 주시겠습니까 무슨 일이야?

,

A.h

#pragma once 
#include <Pimpl.h> 

class A 
{ 
private: 
    struct A_impl; 
    pimpl<A_impl> m_pimpl; 
}; 

B.h

#pragma once 
#include "C.h" 

class B 
{ 
private: 
    C m_C; 
}; 

C.h

#pragma once 
#include <Pimpl.h> 

class C 
{ 
public: 
    // Needed for the PIMPL pattern 
    //~C(); 

private: 
    struct C_impl; 
    pimpl<C_impl> m_pimpl; 
}; 

A.cpp

#include <memory> 
#include "A.h" 
#include "B.h" 
#include <PimplImpl.h> 

struct A::A_impl 
{ 
    std::unique_ptr<B> m_pB; 
}; 

// Ensure all the code for the template is compiled 
template class pimpl<A::A_impl>; 

C.cpp

,
#include <C.h> 
#include <PimplImpl.h> 

struct C::C_impl { }; 

// Needed for the PIMPL pattern 
//C::~C() = default; 

// Ensure all the code for the template is compiled 
template class pimpl<C::C_impl>; 

완성도를 들어, 포스트에서 PIMPL 구현은 위에서 언급 한 :

pimpl.h

#pragma once 
#include <memory> 

template<typename T> 
class pimpl 
{ 
private: 
    std::unique_ptr<T> m; 
public: 
    pimpl(); 
    template<typename ...Args> pimpl(Args&& ...); 
    ~pimpl(); 
    T* operator->(); 
    T& operator*(); 
}; 

PimplImpl.시간

#pragma once 
#include <utility> 

template<typename T> 
pimpl<T>::pimpl() : m{ new T{} } {} 

template<typename T> 
template<typename ...Args> 
pimpl<T>::pimpl(Args&& ...args) 
    : m{ new T{ std::forward<Args>(args)... } } 
{ 
} 

template<typename T> 
pimpl<T>::~pimpl() {} 

template<typename T> 
T* pimpl<T>::operator->() { return m.get(); } 

template<typename T> 
T& pimpl<T>::operator*() { return *m.get(); } 

위의 코드에 대한 몇 가지 참고 사항 :

  • 내 라이브러리의 소비자들에게 AC을 노출하고 B 내부 유지하기 위해 노력하고있어.
  • 여기에 B.cpp가 없으면 empy가됩니다.

답변

2

기본 컴파일러는 사용 지점에서 C 소멸자를 생성하려고하기 때문에 C : C_impl 정의 후 수동으로 C 소멸자를 정의해야하지만 C : C_impl 정의를 찾을 수없는 지점이 될 수 있습니다 (예 : , 그것은 B.cpp 일 수있다).

+0

의미가 있습니다. 사용 시점에 생성 된 것을 알지 못했습니다. 감사! –

1

std::unique_ptr은 인스턴스 생성시 파괴 함수 (즉, 소멸자)를 알아야한다고 생각합니다. 컴파일러는 A.cpp에서 사용할 수있는 정보로 pimpl<C_impl> 개체를 삭제하려고 즉, 사용의 시점에서 생성 ~C() 기본 소멸자와

. 물론 C_impl은 컴파일러가 C_impl 객체를 파괴하는 방법을 모르는 시점에서 선언 된 것이므로 오류가 발생합니다.

주석 처리를 해제하면 ~C();은 컴파일러에서 C_impl을 삭제하는 방법에 대해 걱정하지 않으므로 다른 곳에서 정의됩니다. 귀하의 경우에는 C.cpp에 정의되어 있으며 C_impl의 정의가 알려져 있습니다. 귀하의 편집에 대응

, pimpl<C_impl>에 대한 소멸자에 액세스 할 소멸자와 비 정적 데이터 멤버 (C_impl가 사용 withing에 A.cpp의 점에서 불완전한 유형)이 std::unique_ptr<C_impl> 있습니다.

관련 문제