Указатели против auto_ptr против shared_ptr - PullRequest
8 голосов
/ 26 сентября 2010

Меня недавно познакомили с существованием auto_ptr и shared_ptr, и у меня довольно простой / наивный вопрос.

Я пытаюсь реализовать структуру данных, и мне нужно указать на потомков Node, число которых (больше 1 и его) может измениться. Какая лучшая альтернатива и почему:

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

    private:
        //...
}

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

    private:
        //...
}

Я не уверен, но я думаю, auto_ptr не работает для массивов. Я также не уверен, стоит ли мне использовать двойные указатели. Спасибо за любую помощь.

Ответы [ 4 ]

8 голосов
/ 26 сентября 2010

Вы правы, что auto_ptr не работает для массивов. Когда он уничтожает принадлежащий ему объект, он использует delete object;, поэтому, если вы используете new objects[whatever];, вы получите неопределенное поведение. Возможно, чуть более тонко, auto_ptr не соответствует требованиям «Копируемого» (как стандарт определяет термин), поэтому вы не можете создать контейнер (вектор, deque, list и т. Д.) Из auto_ptr .

A shared_ptr также для отдельного объекта. Это для ситуации, когда вы имеете общее право собственности и вам нужно удалять объект только тогда, когда все владельцы выходят из области видимости. Если что-то не происходит, о чем вы нам не рассказали, велика вероятность, что это тоже не очень хорошо соответствует вашим требованиям.

Возможно, вы захотите взглянуть на еще один новый для вас класс: Boost ptr_vector . По крайней мере, исходя из того, что вы сказали, кажется, что он соответствует вашим требованиям лучше, чем auto_ptr или shared_ptr.

3 голосов
/ 09 октября 2015

Я успешно использовал std::vector<std::shared_ptr<Node> > children в аналогичной ситуации.

Главное преимущество использования вектора shared_ptrs, а не массива, состоит в том, что все управление ресурсами обрабатывается за вас.Это особенно удобно в двух ситуациях:
1) Когда вектор больше не находится в области видимости, он автоматически вызывает delete для всего своего содержимого.В этом случае счетчик ссылок дочернего узла будет уменьшен на 1, и, если на него больше ничего не ссылается, будет вызвано удаление объекта.
2) Если вы ссылаетесь на узел в другом месте, нет риска бытьосталось с висящим указателем на удаленный объект.Объект будет удален только тогда, когда на него больше не будет ссылок.

Если вы не хотите, чтобы поведение было значительно более сложным (возможно, есть причина, по которой массив необходим), я бы предположил, что это может бытьхороший подход для вас.

Простая реализация идеи:

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); 
    }

};
2 голосов
/ 09 октября 2015

auto_ptr устарела в пользу std::unique_ptr и между прочим. std::unique_ptr работает для массивов. Вам просто нужна поддержка c ++ 11. И уже есть много ресурсов об умных указателях и перемещении семантики там. Основное различие между auto_ptr и unique_ptr в том, что auto_ptr делает перемещение при вызове конструктора копирования, а unique_ptr запрещает конструктор копирования, но допускает move при вызове перемещения конструктор. Поэтому вам нужна поддержка c ++ 11 с семантикой перемещения.

1 голос
/ 01 февраля 2017

Страуструп обсуждает вопрос «Что такое auto_ptr и почему нет auto_array» и приходит к выводу, что в последнем нет необходимости, поскольку требуемая функциональность может быть достигнута с помощью вектора.

http://www.stroustrup.com/bs_faq2.html#auto_ptr

...