Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Appropriate use of shared_ptr?

With no experience with shared_ptr<> I am wondering whether the following is an appropriate use case and also whether it is a good idea to return shared_ptr<> to the user.

I have a graph like structure with multiple connections between the nodes. During traversal of the graph each node is assigned a value (computed from connected nodes) and I want the user to be able to access the value easily. The whole thing looks (strongly simplified) like this:

class Pool;
class Node {
    public:
        typedef std::tr1::shared_ptr<Node> Ptr;  
        ...
        void compute_dependencies() { 
            ...
            // calls Pool to get a new Node instance
            dependencies_.push_back(Pool::create_node(...));
            ...
        }

        // evaluate the current node
        void evaluate() { /* use dependencies_ */ };        
        double value() const { if(evaluated) return value_; };

    private:
        std::vector<Node::Ptr> dependencies_;            // vector<Node*> better?
        dbl value_;
}

// Pool creates and owns all nodes
class Pool {
    public:
        static const Node::Ptr create_node(...);         // create a new node
        void traverse_and_evaluate();      

    private:
        std::vector<Node::Ptr> allnodes;   // appropriately sorted to ensure 
                                           // dependencies are evaluated 
        ...
}

and the user calls:

Pool pool();
Node::Ptr node1 = Pool::create_node(...);
Node::Ptr node2 = Pool::create_node(...);
....
pool.traverse_and_evaluate();   
// ready to read out the now populated values
cout << node1->value() << " " << node2->value() << ... 

This has the benefit that the user gets directly access to the nodes he cares about (dependencies are often uninteresting). But I'm not 100% sure whether this is a good idea.

Thanks for your input!

Edit: There are no circular dependencies.

like image 722
bbtrb Avatar asked Apr 15 '11 02:04

bbtrb


2 Answers

shared_ptr is primarily useful for times when an object doesn't have a clear-cut owner (or maybe needs to outlive its owner), so there's no obvious place to destroy it. The shared_ptr essentially becomes the owner, and the object is destroyed when the last shared_ptr to it goes out of scope.

When you've got a clear owner, like your Pool class, and there's no need for the Node objects to outlive the owning Pool, then there really isn't much need for a shared_ptr. You can just destroy the objects in the owner's destructor.

like image 52
Head Geek Avatar answered Nov 04 '22 08:11

Head Geek


I like to provide access to others via weak_ptr, you can construct a weak_ptr< Node > directly from a shared_ptr< Node >.

The user would generally retrieve a weak_ptr from the Pool and then construct a shared_ptr< Node > from the weak_ptr< Node >.lock().

This conveys to the user they don't have ownership rights, and should be careful not to maintain the lock longer than is necessary - or at least it does to me :)

like image 35
Vusak Avatar answered Nov 04 '22 06:11

Vusak