I'm trying to use unique_ptr for a pimpl idiom. So I'm declaring a destructor inside the class so the unique_ptr deletion is not instantiated where the impl class is not defined, and then I define it in another file.
This is my layout:
wrapper.h:
#pragma once
#include <memory>
struct Wrapper
{
class Impl;
~Wrapper();
std::unique_ptr<Impl> _impl;
};
wrapper.cpp:
#include "wrapper.h"
class Wrapper::Impl {};
Wrapper::~Wrapper() = default;
This file compiles just fine. However when compiling main.cpp I get incomplete type errors (see errors below):
main.cpp:
#include "wrapper.h"
int main()
{
Wrapper w;
return 0;
}
However, if I add the two lines from wrapper.cpp at the end of main.cpp, it compiles just fine. I don't understand two things:
- Why does the error happen in the first place? I thought declaring the destructor in the class moves the point of delete invocation?
- How come adding code at the end of the main.cpp file affects this error? I though "If the default deleter is used, T must be complete at the point in code where the deleter is invoked, which happens in the destructor" (from cppreference).
What am I missing?
UPDATE:
Following @AdrianMole's suggestion I added a ctor declaration inside class Wrapper definition and for some reason it fixed the error, even though the error (and the unique_ptr spec) refers to the destructor.
Updated wrapper.h:
struct Wrapper
{
class Impl;
Wrapper();
~Wrapper();
std::unique_ptr<Impl> _impl;
};
So I'm adding a question:
- Why does adding a constructor declaration fixes this?
These are the errors I get with MSVC, but similar errors happen with clang or gcc (I tried online compilers):
memory(2536,1): error C2027: use of undefined type 'Wrapper::Impl'
wrapper.h(7): message : see declaration of 'Wrapper::Impl'
memory(2535): message : while compiling class template member function 'void std::default_deleteWrapper::Impl::operator ()(_Ty *) noexcept const'
with [ _Ty=Wrapper::Impl ]
memory(2647): message : see reference to function template instantiation 'void std::default_deleteWrapper::Impl::operator ()(_Ty *) noexcept const' being compiled
with [ _Ty=Wrapper::Impl ]
memory(2574): message : see reference to class template instantiation 'std::default_deleteWrapper::Impl' being compiled
wrapper.h(9): message : see reference to class template instantiation 'std::unique_ptrWrapper::Impl,std::default_delete<Wrapper::Impl>' being compiled
memory(2536,25): error C2338: can't delete an incomplete type
memory(2537,1): warning C4150: deletion of pointer to incomplete type 'Wrapper::Impl'; no destructor called
wrapper.h(7): message : see declaration of 'Wrapper::Impl'
Wrapper::Wrapper() : _impl(new Impl) {}
too inwrapper.cpp
? – m88Wrapper
destructor but where you define theImpl
class. I guess the default constructor for thestd::unique_ptr<Impl>
object needs to know the full definition ofImpl
. – Adrian Moleunique_ptr
object.) But yeah - not sure why adding the definition after the code fixes that. – Adrian Mole