Can you put a pimpl-Class inside a vector

658 views Asked by At

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

There are 2 answers

3
m.s. On BEST ANSWER

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

4
Rudolfs Bundulis On

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;
}