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!
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.
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))); .
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.
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.
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 Unit
s (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?"
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With