Используя умные указатели в C++ бинарный поиск в дереве
я реализовал двоичное дерево поиска в c++. Вместо того, чтобы использовать голые указатели для указания на детей узлов, я использовал std::shared_ptr
. Узлы дерева реализованы следующим образом
struct treeNode;
typedef std::shared_ptr<treeNode> pTreeNode;
struct treeNode {
T key;
pTreeNode left;
pTreeNode right;
treeNode(T key) : key(key), left(nullptr), right(nullptr) {}
};
при удалении узла из BST, один из случаев, когда узел имеет только один дочерний. Узел просто заменяется этим дочерним элементом, как показано ниже:
| remove node
node ---------> |
right
right
в аналогичной реализации Java это может быть закодировано как:
node = node.getRight();
в моем c++ реализация это:
node = node->right;
где узел имеет тип pTreeNode
.
при вызове оператора = на pTreeNode
(std::shared_ptr<TreeNode>
),'ы будет называться. Количество общих указателей, указывающих на базовый TreeNode
равно 1, следовательно,TreeNode
разрушается, освобождая свою память. Когда TreeNode
(по умолчанию) вызывается деструктор, каждый из его членов уничтожается. Это, безусловно, приведет к pTreeNode right
член разрушается. Проблема в том, что node->right
это то, что назначается node
. При тестировании моего BST он работает нормально без ошибок / утечек памяти.
- то, что я делаю, небезопасно?
- если это небезопасно, что я мог сделать, чтобы обойти эту проблему?
"хак", который я полагал, может работать, будет сделать еще один указатель, чтобы увеличить его количество ссылок. Будет ли это адекватным решением?
//increase reference to node->right by 1 so it doesn't get destroyed
pTreeNode temp(node->right);
node = node->right;
2 ответов
вы, по-видимому, предполагаете, что в
node = right;
shared_ptr
оператор присваивания может уменьшить количество узлов до завершения чтения из right
(или перед увеличением количества ссылок, используемых right
). Однако, согласно cppreference, используя
template<typename T>
template<typename U>
std::shared_ptr<T> &std::shared_ptr<T>::operator =(const std::shared_ptr<U> &);
as
node = right; // std::shared_ptr<treeNode>
эквивалентно
std::shared_ptr<treeNode>(right).swap(node);
, который является безопасным, потому что right
скопировать до старое значение node
разрушен. Как кроме того, я сам реализовал общий указатель, и я следил за тем, чтобы" очистка " старого значения была последние что я делаю внутри operator =
именно, чтобы избежать таких проблем.
- то, что я делаю, небезопасно?
нет, насколько я вижу, это безопасно. The left
или right
экземпляры узлов будут сохраняться до тех пор, пока их количество ссылок не упадет до нуля.
- если это небезопасно, что я мог сделать, чтобы обойти эту проблему?
единственное, что вы должны знать, это не раздавать какие-либо узлы как shared_ptr
' s вне реализации дерева. Они должны будь std::weak_ptr
или сырые указатели.