ciyo
ciyo

Reputation: 735

Initializing Unique Pointers as a Class Member

I am working on a tree structure that has a vector of unique pointers as a class member. While working on it, I realised that I am not sure how to initialize a unique pointer as a class member if the object, which the unique pointer will own, comes as a parameter.

So, I am simply asking: How I should initialize unique pointers as a class member if the object that will be owned comes as a parameter?

Should I use new ( addTheObject(new Object()) ) and then use std::make_unique? Should I pass the object as unique_ptr ( addTheObject(std::unique_ptr<Object>& theObject) ) and use std::move(theObject)?

What is the correct way to handle this?

In case you need more concrete example:

I have a DT_Node class, which is a node of a tree, and I will construct a tree using DT_Node.

DT_Node has a method called addChild() that is used to insert children into its node vector.

DT_Node will be used in different cpp files to construct a tree, which means another cpp file will use addChild() method to add the children of the node.

// DT_Node.hpp
class DT_Node
{
public:

    DT_Node();
    virtual ~DT_Node();

    virtual void decide() = 0;

    virtual void addChild( ??? );

private:

    std::vector< std::unique_ptr<DT_Node> > mNodes;
};

// DT_Node.cpp
DT_Node::DT_Node()
{

}

DT_Node::~DT_Node()
{
    mNodes.clear();
}

void DT_Node::addChild( ??? )
{
    ???
}

Upvotes: 2

Views: 2725

Answers (3)

BiagioF
BiagioF

Reputation: 9705

std::unique_ptr keeps the own of the pointed object. That means if you want to pass it as a parameter, you have to move the ownership.

Something like (note the move and &&-reference):

void addChild(std::unique_ptr<Node>&& iNode) {
  mNodes.emplace_back(std::move(iNode));
}

Finally, I'd strongly suggest you take a look at this Herb Sutter Video. It gives some useful advice on data structures with smart pointers.

Upvotes: 3

ObliteratedJillo
ObliteratedJillo

Reputation: 5156

Assuming that DT_Node is not a pure virtual base class , this is the code snippet. You will need a copy constructor as well. Two versions of the addChild is used which is self explanatory.

  class DT_Node
{
public:    
    DT_Node();
    DT_Node(const DT_Node& other); // copy constructor will be needed
    virtual void addChild(std::unique_ptr<DT_Node>&& node); // move from source
    virtual void addChild(const std::unique_ptr<DT_Node>& node);  //non destructible source

private:    
    std::vector<std::unique_ptr<DT_Node> > mNodes;
};    

void DT_Node::addChild(std::unique_ptr<DT_Node>&& node) 
{
    mNodes.push_back(std::move(node));
}
void DT_Node::addChild(const std::unique_ptr<DT_Node>& node)  
{

    std::unique_ptr<DT_Node> new_node = std::make_unique<DT_Node>(*node);
    mNodes.push_back(std::move(new_node));
}

Upvotes: 0

What you need is:

void DT::Node::addChild(std::unique_ptr<DT_Node>&& child) {
    mNodes.emplace_back(std::move(child));
}

By the way, your title is misleading. The unique_ptr is not a member (it is contained in a member), and you are not definitely not initializing a member (for which you would use the member initializer list syntax in the constructor).

Upvotes: 8

Related Questions