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