Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

std::unique_ptr attempting to reference a deleted function

Tags:

c++

c++11

I've been on Unity for quite a while and came back to do some C++ using Visual Studio 2015. I came across this class definition

class A
{
public:
  A();
  virtual ~A();
  A(const A&) = delete;
  A& operator=(const A&) = delete;

private:
  …
}

This class is dynamically allocated like the following:

ObjPtr obj = ObjPtr(new A());

where ObjPtr is a type defined and looks like:

typedef std::unique_ptr<A> objPtr;

and adding these created objects using to a std::vector<ObjPtr> using std::move. At one point, I need to loop through the list of objects, and if I find something that satisfies my criteria, keep a copy of it.

ObjPtr keep;

for(auto& object : GetObjectList() )
{
  if(/*check if its the object I want*/)
  {
    keep = object;
  }
}

Where GetObjectList returns a const std::vector<ObjPtr>&.

But I'm getting an “attempting to reference a deleted function”. I did some googling and tried to remove the = delete part and even commented the 2 lines out. I even tried to do

ObjPtr keep = std::move(object);

But I'm still getting the deleted function error. Can anyone see what I'm doing wrong or point me to some resources that can help?

like image 306
dwnenr Avatar asked Nov 21 '15 21:11

dwnenr


1 Answers

A std::unique_ptr cannot be copied. Even if the managed object could (but yours can't).

You have a couple of alternatives here (all with different effects):

  • Change the type of keep to a non-owning raw pointer (aka A *) and use keep = object.get();. This is safe if and only if you know you won't use keep longer than ObjectList (or, more precisely, the object you take the address of) exists.

  • Move the std::unique_ptr out of the container, that is, use keep = std::move(object);. Of course, now you have a gap in ObjectList. (I realize you have edited your question to say that ObjectList is const which means that you cannot modify and hence not move objects out of it.)

  • Change the type of ObjPtr to std::shared_ptr<A> if you want shared ownership semantics.

  • If you absolutely want a copy of the object, you could add a virtual member function to A that clones the object polymorphically.

    class A
    {
    public:
      virtual std::unique_ptr<A> clone() = 0;
      …
    };
    

    You then implement that function in every leaf class derived from A. In your loop, you then use keep = object->clone();. For this, you probably want to make the copy constructor protected but don't delete it.

    Don't use keep = std::make_unique<A>(*object); because it would not respect the actual (dynamic) type of the object and always slice to an A. (Since your A is not copyable, it wouldn't work anyway.)

like image 158
5gon12eder Avatar answered Oct 14 '22 03:10

5gon12eder