반응형
class SessionImpl;

class Session
{
public:
    Session() = default;
    virtual ~Session() = default;
private:
    std::unique_ptr<SessionImpl> pImpl_;
};

이 코드를 빌드하면 visual studio 에서 아래 오류가 발생한다.

 

오류 C2027 정의되지 않은 형식 'SessionImpl'을(를) 사용했습니다. 
경고 C4150 불완전한 형식 'SessionImpl'에 대한 포인터를 삭제했습니다. 소멸자가 호출되지 않습니다. 
오류 C2338 can't delete an incomplete type 

이유는 SessionImpl 이 전방선언되어 있고 Session의 생성자/소멸자가

SessionImpl의 정의를 알 수 없기 때문이다.

 

Session의 ctor와 dtor 를 default 키워드를 사용해 정의를 생략했는데,

이 경우 Session.cpp에서 SessionImpl.h를 include 하더라도 위 오류가 발생한다.

 

Session의 ctor와 dtor 정의 앞에 SessionImpl의 정의가 오면된다.

 

Session.h 는 아래 처럼 default를 제거하고

class SessionImpl;

class Session
{
public:
    Session();
    virtual ~Session();
private:
    std::unique_ptr<SessionImpl> pImpl_;
};

Session.cpp 에 ctor와 dtor 정의를 작성하면 자연스럽게 해결된다.

#include "Session.h"
#include "SessionImpl.h"

Session::Session()
{
}
Session::~Session()
{
}

정리해보면 pimpl 관용구의 이점을 위해 전방선언했지만, ctor/dtor를 default 키워드로 정의하다보니 발생한 오류이다.

pimpl 관용구의 사용목적상 전방선언을 유지하기 위해 ctor/dtor의 default키워드를 사용하지 않으면되는 문제다.

 

 

번외로, Visual Studio 오류 창에서 C2338 can't delete an incomplete type 를 따라 들어가보면

memory 헤더에서 assert 된 지점을 볼 수 있는데

 

이 부분에서 unique_ptr의 소멸처리 구현부가 sizeof(_Ty)를 통해 사이즈를 확인하므로

템플릿 인자의 정의 유무를 체크하는 부분이 재밌것 같다.

	// TEMPLATE CLASS default_delete
template<class _Ty>
	struct default_delete
	{	// default deleter for unique_ptr
	constexpr default_delete() _NOEXCEPT = default;

	template<class _Ty2,
		class = typename enable_if<is_convertible<_Ty2 *, _Ty *>::value,
			void>::type>
		default_delete(const default_delete<_Ty2>&) _NOEXCEPT
		{	// construct from another default_delete
		}

	void operator()(_Ty *_Ptr) const _NOEXCEPT
		{	// delete a pointer
		static_assert(0 < sizeof (_Ty),
			"can't delete an incomplete type");
		delete _Ptr;
		}
	};

 

 

참고 : 

https://stackoverflow.com/questions/44633726/circular-dependency-cant-delete-an-incomplete-type

반응형
반응형

Windows VIA c/c++ 소스 예제에 Clean.bat 란 배치파일이 있어서 조금 수정해서 사용중입니다.

역시 배치가 편하네요~


Clean.bat

반응형

+ Recent posts