Dowemo
0 0 0 0


Question:

I'm new to move semantics in C++11 and I don't know very well how to handle unique_ptr parameters in constructors or functions. Consider this class referencing itself:

#include <memory>
class Base
{
  public:
    typedef unique_ptr<Base> UPtr;
    Base(){}
    Base(Base::UPtr n):next(std::move(n)){}
    virtual ~Base(){}
    void setNext(Base::UPtr n)
    {
      next = std::move(n);
    }
  protected :
    Base::UPtr next;
};

Is this how I should write functions taking unique_ptr arguments?

And do I need to use std::move in the calling code?

Base::UPtr b1;
Base::UPtr b2(new Base());
b1->setNext(b2); //should I write b1->setNext(std::move(b2)); instead?

Best Answer:


Edit: This answer is wrong, even though, strictly speaking, the code works. I'm only leaving it here because the discussion under it is too useful. This other answer is the best answer given at the time I last edited this: How do I pass a unique_ptr argument to a constructor or a function?

The basic idea of ::std::move is that people who are passing you the unique_ptr should be using it to express the knowledge that they know the unique_ptr they're passing in will lose ownership.

This means you should be using an rvalue reference to a unique_ptr in your methods, not a unique_ptr itself. This won't work anyway because passing in a plain old unique_ptr would require making a copy, and that's explicitly forbidden in the interface for unique_ptr. Interestingly enough, using a named rvalue reference turns it back into an lvalue again, so you need to use ::std::moveinside your methods as well.

This means your two methods should look like this:

Base(Base::UPtr &&n) : next(::std::move(n)) {} // Spaces for readability
void setNext(Base::UPtr &&n) { next = ::std::move(n); }

Then people using the methods would do this:

Base::UPtr objptr{ new Base; }
Base::UPtr objptr2{ new Base; }
Base fred(::std::move(objptr)); // objptr now loses ownership
fred.setNext(::std::move(objptr2)); // objptr2 now loses ownership

As you see, the ::std::move expresses that the pointer is going to lose ownership at the point where it's most relevant and helpful to know. If this happened invisibly, it would be very confusing for people using your class to have objptr suddenly lose ownership for no readily apparent reason.




Copyright © 2011 Dowemo All rights reserved.    Creative Commons   AboutUs