Реализация контейнеров с использованием умных указателей - PullRequest
4 голосов
/ 29 марта 2011

Хорошо, так что все знают, что необработанных указателей следует избегать, как чумы, и предпочитать умные указатели, но применим ли этот совет при реализации контейнера?Вот что я пытаюсь сделать:

template<typename T> class AVLTreeNode {
public:
    T data;
    unique_ptr<AVLTreeNode<T>> left, right;
    int height;
}

Unique_ptr может сделать функции контейнера более громоздкими для записи, потому что я не могу иметь несколько необработанных указателей, временно указывающих на один и тот же объект элегантным способом.Например:

unique_ptr<AVLTreeNode<T>> rotate_right(unique_ptr<AVLTreeNode<T>> n1)
{
    unique_ptr<AVLTreeNode<T>> n2 = n1->left;

    n1->left = n2->right;
    n2->right = n1;
    // n1 must now be referenced through the longer name n2->right from now on
    n2->right->recalculate_height();
    n2->recalculate_height();

    return n2;
}

(В этом примере это не имеет большого значения, но я могу представить, как это может стать проблемой).Должен ли я воспринимать подобные проблемы как сильный намек на то, что контейнеры должны быть реализованы со старыми добрыми new, delete и необработанными указателями?Кажется, что очень трудно просто написать деструктор.

Ответы [ 5 ]

6 голосов
/ 29 марта 2011

Я обычно не использую умные указатели при реализации контейнеров, как вы показываете.Необработанные указатели (imho) не , которых следует избегать, как чумы.Используйте умный указатель, когда вы хотите обеспечить владение памятью.Но обычно в контейнере контейнер владеет памятью, на которую указывают указатели, составляющие структуру данных.

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

Поверьте мне, я 'не анти-смарт-указатель.Я тот, кто изобрел unique_ptr.Но unique_ptr - это просто еще один инструмент в наборе инструментов.Наличие хороших умных указателей в ящике для инструментов не является панацеей, и использование их вслепую для всего не заменяет тщательного проектирования.

Обновление для ответа на комментарий (поле для комментариев былослишком маленький):

Я часто использую сырые указатели (которыми редко владею).Хорошая выборка моего стиля кодирования существует в проекте с открытым исходным кодом libc ++ .Можно просмотреть исходный код по ссылке «Обзор SVN».

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

Самая важная вещьв том, что я никогда не выделяю какой-либо ресурс, не зная, какому объекту принадлежит этот ресурс, будь то умный указатель, контейнер или что-то еще.

3 голосов
/ 29 марта 2011

Код, который вы представили, компилируется без проблем

#include <memory>
template<typename T> class AVLTreeNode {
public:
    T data;
    std::unique_ptr<AVLTreeNode<T>> left, right;
    int height;
};
int main()
{
    AVLTreeNode<int> node;
}

тестовая подборка: https://ideone.com/aUAHs

Лично я использовал умные указатели для деревьев, даже когда единственное, что у нас было, это std::auto_ptr

Что касается rotate_right, его можно реализовать с помощью пары вызовов unique_ptr::swap

0 голосов
/ 20 декабря 2016

У Herb Shutter очень четкое указание о том, что не следует использовать shared_ptr в качестве параметров в его серии GoTW :

Указание: не передавайте умный указатель в качестве параметра функции, если вы хотите использовать или манипулировать сам умный указатель, например, для делиться или передавать право собственности.

и это ...

Указание: предпочитайте передавать объекты по значению, * или &, а не по умному указатель.

0 голосов
/ 29 марта 2011

std::shared_ptr не имеет этих ограничений.В частности, несколько shared_ptr экземпляров могут ссылаться на один и тот же объект.

0 голосов
/ 29 марта 2011

Небольшое исправление: не следует избегать необработанных указателей, таких как чума (к сожалению, не все знали об этом), но следует по возможности избегать ручного управления памятью (используя контейнеры вместо динамического массива или интеллектуальных указателей), так что в вашей функции просто выполните get () для вашего unique_ptr для временного хранения.

...