使用pimpl移动类将无法编译

时间:2014-02-26 16:45:10

标签: c++ c++11 pimpl-idiom opaque-pointers

在下面的例子中,如何正确调用~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()

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
}

编译器输出:

+ 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.

1 个答案:

答案 0 :(得分:4)

析构函数工作正常,因为析构函数的(空)主体位于C源文件中,可以访问Impl的完整定义。然而,移动构造函数和移动赋值在标题中默认(定义),没有Impl的定义。

您可以执行的是标题中的C(C&&);和源文件中的C::C(C&&) = default;