In the following example, how is it possible that ~CImpl is called correctly but when the class needs to be moved, the compiler says it has an incomplete type?
If the declaration of Impl is moved to the header it works, my question is how come the destructor is called fine so it doesn't seem that the type is incomplete, but the problem appears when moving.
file: C.hpp
#include <memory>
class Impl;
class C
{
public:
C();
~C();
C(C&&) = default;
C& operator=(C&&) = default;
std::unique_ptr<Impl> p;
};
file C.cpp
#include "C.hpp"
#include <iostream>
using namespace std;
class Impl
{
public:
Impl() {}
virtual ~Impl() = default;
virtual void f() = 0;
};
class CImpl: public Impl
{
public:
~CImpl()
{
cout << "~CImpl()" << endl;
}
void f()
{
cout << "f()" << endl;
}
};
C::C():
p(new CImpl())
{}
C::~C()
file: main.cpp
#include <iostream>
#include <vector>
#include "C.hpp"
using namespace std;
int main(int argc, char *argv[])
{
vector<C> vc;
// this won't compile
//vc.emplace_back(C());
C c;
C c2 = move(c); // this won't compile
}
Compiler output:
+ clang++ -std=c++11 -Wall -c C.cpp
+ clang++ -std=c++11 -Wall -c main.cpp
In file included from main.cpp:3:
In file included from ./C.hpp:1:
In file included from /usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/memory:80:
/usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/bits/unique_ptr.h:65:16: error: invalid application of 'sizeof' to an incomplete type 'Impl'
static_assert(sizeof(_Tp)>0,
^~~~~~~~~~~
/usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/bits/unique_ptr.h:184:4: note: in instantiation of member function
'std::default_delete<Impl>::operator()' requested here
get_deleter()(__ptr);
^
./C.hpp:12:5: note: in instantiation of member function 'std::unique_ptr<Impl, std::default_delete<Impl> >::~unique_ptr' requested here
C(C&&) = default;
^
./C.hpp:3:7: note: forward declaration of 'Impl'
class Impl;
^
1 error generated.
C c2 = move(c);
. Does it still compile? – Hatred