В следующем примере, как это возможно, что ~ CImpl вызывается правильно, но когда класс должен быть перемещен, компилятор говорит, что он имеет неполный тип?
Если объявление Impl перемещено в заголовок, оно работает, мой вопрос в том, почему деструктор называется нормально, так что не кажется, что тип является неполным, но проблема возникает при перемещении.
файл: C.hpp
#include <memory>
class Impl;class C
{
public:
C();
~C();
C(C&&) = default;
C& operator=(C&&) = default;
std::unique_ptr<Impl> p;
};
файл 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()
файл: 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
}
Выход компилятора:
+ 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 с доступом к полному определению Impl
, Конструктор перемещения и назначение перемещения, однако, по умолчанию (определены) в заголовке без определения Impl
,
Что вы можете сделать, это C(C&&);
в шапке и C::C(C&&) = default;
в исходном файле.
Других решений пока нет …