Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Returning a vector of unique_ptr from function

Tags:

I am currently going through the book Head First Object Oriented Analysis and Design and also getting used to some of the features of C++11 (especially unique_ptr and move semantics) at the same time. In the book, they give the design of a strategy board game as an example. It has a board, tiles and units on tiles. The code is in Java and I was trying to rewrite it in C++. In Java, the tile class is as follows:

public class Tile
{
    private List units;

    public Tile()
    {
        units = new LinkedList();
    }

    protected void addUnit(Unit unit)
    {
        units.add(unit);
    }

    protected List getUnits()
    {
        return units;
    }
}

I did the same thing in c++ first using shared_ptr. It worked but very slow compared to my second version which used raw pointers. I then tried unique_ptr:

class Tile
{

public:
  Tile();
  virtual ~Tile();

  void addUnit()
  {
    mUnits.push_back(std::unique_ptr<Unit>(new Unit());
  }

  std::vector<std::unique_ptr<Unit>> getUnits()
  {
    return mUnits;
  }

private:
  std::vector<std::unique_ptr<Unit>> mUnits;

};

the compiler does not like the getUnits. From what I understand it comes from the fact that the copy constructor is disabled in the unique_ptr. How would you return the list of vectors? Thanks!

like image 685
darkman Avatar asked Sep 06 '12 14:09

darkman


People also ask

What happens when you return a unique_ptr?

If a function returns a std::unique_ptr<> , that means the caller takes ownership of the returned object. class Base { ... }; class Derived : public Base { ... }; // Foo takes ownership of |base|, and the caller takes ownership of the returned // object.

Can I have a vector of unique_ptr?

This means that you can't make copies of a unique_ptr (because then two unique_ptr s would have ownership), so you can only move it. D.R. Since there can be only one, one should also be able to pass a temporary directly to the vector: vec. push_back(std::unique_ptr<int>(new int(1))); .

Can you copy unique_ptr?

A unique_ptr does not share its pointer. It cannot be copied to another unique_ptr , passed by value to a function, or used in any C++ Standard Library algorithm that requires copies to be made. A unique_ptr can only be moved.

What does Make_unique return?

Returns: A unique_ptr to an object of type U , initialized to move(value) . Remarks: This overload shall only participate in overload resolution when U is not an array type.


1 Answers

A value returned in C++ incurs a copy - if that's what you want, you can't use unique_ptr or have to make a manual copy and std::move it. However, I take you only want to provide access to the Units (for whatever reason...), so simply return a reference:

std::vector<std::unique_ptr<Unit>> const& getUnits() const
{
  return mUnits;
}

(The const is only needed if you don't want to give write access into the vector.)

Now, a few questions arise still: Why is ~Tile virtual? I see no need.

Why do you use an owning ptr to point to the units? In the original Java code, you get handed a reference to an external Unit and only store a reference - if the Tile in the Java code is destroyed, the units are not (from what I can see), as long as they are referenced somewhere else. To achieve the exact same in C++, you were correct in using shared_ptr.

Of course, you could just clarify who is the real owner of the units and operate accordingly - if it is not Tile, use a raw pointer. See also "Which kind of pointer do I use when?"

like image 180
Xeo Avatar answered Sep 26 '22 15:09

Xeo