Используя умные указатели в 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или сырые указатели.