Can you put a pimpl-Class inside a vector

2019-07-08 02:40发布

I have a class implemented using the PImpl Ideom:

class FooImpl {};

class Foo
{
   unique_ptr<FooImpl> myImpl;
public:
   Foo();
   ~Foo();
};

And now I want to put this into a std::vector

void Bar()
{
   vector<Foo> testVec;
   testVec.resize(10);
}

But when I do that, I get a compiler error (VC++ 2013)

error C2280: 'std::unique_ptr>::unique_ptr(const std::unique_ptr<_Ty,std::default_delete<_Ty>> &)' : attempting to reference a deleted function

I get the same error with testVec.emplace_back(); and testVec.push_back(std::move(Foo()));

(As a workaround, using vector<unique_ptr<Foo>> seems to work, but I don't understand why the code above doesn't work.)

Working example: http://coliru.stacked-crooked.com/a/b274e1209e47c604

2条回答
地球回转人心会变
2楼-- · 2019-07-08 03:03

Since std::unique_ptr is not copyable, class Foo does not have a valid copy constructor.

You could either deep copy or use a move constructor:

#include <memory>
#include <vector>

class FooImpl {};

class Foo
{
   std::unique_ptr<FooImpl> myImpl;
public:
   Foo( Foo&& f ) : myImpl( std::move( f.myImpl ) ) {}
   Foo(){}
   ~Foo(){}
};

int main() {
    std::vector<Foo> testVec;
    testVec.resize(10);
    return 0;
}

Live example: https://ideone.com/HYtPMu

查看更多
一纸荒年 Trace。
3楼-- · 2019-07-08 03:15

So what happens is that the vector template tries to access the copy constructor of the Foo class. You have not provided one, so the compiler tries to generate a default implementation that calls the copy constructor on all members. Since the std::unique_ptr does not have a copy constructor from another std::unique_ptr (which is logical because it does not know how to copy the object) the compiler cannot generate the assignment operator for Foo and it fails. So what you can do is provide a copy constructor for the Foo class and decide how to handle the pointer:

#include <memory>
#include <vector>

using namespace std;
class FooImpl {};

class Foo
{
    unique_ptr<FooImpl> myImpl;
public:
    Foo()
    {
    }
    ~Foo()
    {
    }
    Foo(const Foo& foo)
    {
        // What to do with the pointer?
    }
    Foo& operator= (const Foo& foo)
    {
        if (this != &foo)
        {
            // What to do with the pointer?
        }
        return *this;
    }
};

int main(int argc, char** argv)
{
    vector<Foo> testVec;
    testVec.resize(10);
    return 0;
}
查看更多
登录 后发表回答