Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pointers vs auto_ptr vs shared_ptr

I was recently introduced to the existence of auto_ptr and shared_ptr and I have a pretty simple/naive question.

I try to implement a data structure and I need to point to the children of a Node which (are more than 1 and its) number may change. Which is the best alternative and why:

class Node
{
    public:
        // ...
        Node *children;

    private:
        //...
}

class Node
{
    public:
        // ...
        share_ptr<Node> children;

    private:
        //...
}

I am not sure, but I think auto_ptr does not work for arrays. I am not, also, sure about whether I should use double pointers. Thanks for any help.

like image 767
Dimitris Leventeas Avatar asked Sep 25 '10 21:09

Dimitris Leventeas


People also ask

Why was auto_ptr removed?

Single most important reason as to why auto_ptr was deprecated in favor of smart-pointer is assignment-semantics If it wasn't for that reason, they would have added all the new goodies of move semantics to the auto_ptr instead of deprecating it.

What is the difference between the two smart pointers shared_ptr and unique_ptr?

Use unique_ptr when you want to have single ownership(Exclusive) of the resource. Only one unique_ptr can point to one resource. Since there can be one unique_ptr for single resource its not possible to copy one unique_ptr to another. A shared_ptr is a container for raw pointers.

Is auto_ptr deprecated?

auto_ptr was fully removed in C++17.

Is shared_ptr a smart pointer?

The shared_ptr type is a smart pointer in the C++ standard library that is designed for scenarios in which more than one owner might have to manage the lifetime of the object in memory.


2 Answers

You're right that auto_ptr doesn't work for arrays. When it destroys the object it owns, it uses delete object;, so if you used new objects[whatever];, you'll get undefined behavior. Perhaps a bit more subtly, auto_ptr doesn't fit the requirements of "Copyable" (as the standard defines the term) so you can't create a container (vector, deque, list, etc.) of auto_ptr either.

A shared_ptr is for a single object as well. It's for a situation where you have shared ownership and need to delete the object only when all the owners go out of scope. Unless there's something going on that you haven't told us about, chances are pretty good that it doesn't fit your requirements very well either.

You might want to look at yet another class that may be new to you: Boost ptr_vector. At least based on what you've said, it seems to fit your requirements better than either auto_ptr or shared_ptr would.

like image 137
Jerry Coffin Avatar answered Oct 05 '22 13:10

Jerry Coffin


I have used std::vector<std::shared_ptr<Node> > children successfully in a similar situation.

The main benefit of using a vector of shared_ptrs rather than an array is that all of the resource management is handled for you. This is especially handy in two situations:
1) When the vector is no longer in scope, it automatically calls delete on all of its contents. In this case, the reference count of the child Node will drop by 1 and if nothing else is referencing it, delete will be called on the object.
2) If you are referencing the Node elsewhere, there is no risk of being left with a dangling pointer to a deleted object. The object will only be deleted when there are no more references to it.

Unless you want behaviour that is substantially more complicated (perhaps there is a reason why an array is necessary), I would suggest this might be a good approach for you.

A simple implementation of the idea:

class Node {
private:
    T contents;
    std::vector<std::shared_ptr<Node> > children;

public:
    Node(T value) : contents(value) {};

    void add_child(T value) { 
        auto p = std::make_shared<Node>(value); 
        children.push_back(p); 
    }

    std::shared_ptr<Node> get_child(size_t index) { 
        // Returning a shared pointer ensures the node isn't deleted
        // while it is still in use.
        return children.at(index);
    }

    void remove_child(size_t index) { 
        // The whole branch will be destroyed automatically.
        // If part of the tree is still needed (eg. for undo), the
        // shared pointer will ensure it is not destroyed.
        children.erase(children.begin() + index); 
    }

};
like image 20
QuesterZen Avatar answered Oct 05 '22 14:10

QuesterZen