我正在尝试用unique_ptr
实现BST。我有一个shared_ptr
的工作程序。如何使用unique_ptr来强制BinarySearchTree的单一所有权语义?
当我用unique_ptr
替换shared_ptr
时,我会出现无法理解的编译错误。
#include <iostream>
#include <memory>
template<class T>
class BinarySearchTree{
struct TreeNode;
typedef std::shared_ptr<TreeNode> spTreeNode;
struct TreeNode{
T data;
spTreeNode left;
spTreeNode right;
TreeNode(const T & value):data(value),left(nullptr),right(nullptr){}
};
spTreeNode root;
bool insert(spTreeNode node);
void print(const spTreeNode) const ;
public:
BinarySearchTree();
void insert( const T & node);
void print()const;
};
template<class T>
BinarySearchTree<T>::BinarySearchTree():root(nullptr){}
template<class T>
void BinarySearchTree<T>::insert(const T & ref)
{
TreeNode *node = new TreeNode(ref);
if (root==nullptr)
{
root.reset(node);
}
else
{
spTreeNode temp = root;
spTreeNode prev = root;
while (temp)
{
prev = temp;
if (temp->data < ref)
temp = temp->right;
else
temp = temp->left;
}
if (prev->data < ref)
prev->right.reset(node);
else
prev->left.reset(node);
}
}
template<class T>
void BinarySearchTree<T>::print()const
{
print(root);
}
template<class T>
void BinarySearchTree<T>::print(const spTreeNode node)const
{
if (node==nullptr)
return;
print(node->left);
std::cout << node->data<< std::endl;
print(node->right);
}
int main()
{
BinarySearchTree<int> bst;
bst.insert(13);
bst.insert(3);
bst.insert(5);
bst.insert(31);
bst.print();
return 0;
}
编辑:编译错误,以防有人感兴趣。警告:文字墙。
prog.cpp: In instantiation of ‘void BinarySearchTree<T>::insert(const T&) [with T = int]’:
prog.cpp:75:18: required from here
prog.cpp:39:27: error: use of deleted function ‘std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = BinarySearchTree<int>::TreeNode; _Dp = std::default_delete<BinarySearchTree<int>::TreeNode>]’
spTreeNode temp = root;
^
In file included from /usr/include/c++/4.8/memory:81:0,
from prog.cpp:2:
/usr/include/c++/4.8/bits/unique_ptr.h:273:7: error: declared here
unique_ptr(const unique_ptr&) = delete;
^
prog.cpp:40:27: error: use of deleted function ‘std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = BinarySearchTree<int>::TreeNode; _Dp = std::default_delete<BinarySearchTree<int>::TreeNode>]’
spTreeNode prev = root;
^
In file included from /usr/include/c++/4.8/memory:81:0,
from prog.cpp:2:
/usr/include/c++/4.8/bits/unique_ptr.h:273:7: error: declared here
unique_ptr(const unique_ptr&) = delete;
^
prog.cpp:43:18: error: use of deleted function ‘std::unique_ptr<_Tp, _Dp>& std::unique_ptr<_Tp, _Dp>::operator=(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = BinarySearchTree<int>::TreeNode; _Dp = std::default_delete<BinarySearchTree<int>::TreeNode>]’
prev = temp;
^
In file included from /usr/include/c++/4.8/memory:81:0,
from prog.cpp:2:
/usr/include/c++/4.8/bits/unique_ptr.h:274:19: error: declared here
unique_ptr& operator=(const unique_ptr&) = delete;
^
prog.cpp:45:22: error: use of deleted function ‘std::unique_ptr<_Tp, _Dp>& std::unique_ptr<_Tp, _Dp>::operator=(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = BinarySearchTree<int>::TreeNode; _Dp = std::default_delete<BinarySearchTree<int>::TreeNode>]’
temp = temp->right;
^
In file included from /usr/include/c++/4.8/memory:81:0,
from prog.cpp:2:
/usr/include/c++/4.8/bits/unique_ptr.h:274:19: error: declared here
unique_ptr& operator=(const unique_ptr&) = delete;
^
prog.cpp:47:22: error: use of deleted function ‘std::unique_ptr<_Tp, _Dp>& std::unique_ptr<_Tp, _Dp>::operator=(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = BinarySearchTree<int>::TreeNode; _Dp = std::default_delete<BinarySearchTree<int>::TreeNode>]’
temp = temp->left;
^
In file included from /usr/include/c++/4.8/memory:81:0,
from prog.cpp:2:
/usr/include/c++/4.8/bits/unique_ptr.h:274:19: error: declared here
unique_ptr& operator=(const unique_ptr&) = delete;
^
prog.cpp: In instantiation of ‘void BinarySearchTree<T>::print() const [with T = int]’:
prog.cpp:79:15: required from here
prog.cpp:59:15: error: use of deleted function ‘std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = BinarySearchTree<int>::TreeNode; _Dp = std::default_delete<BinarySearchTree<int>::TreeNode>]’
print(root);
^
In file included from /usr/include/c++/4.8/memory:81:0,
from prog.cpp:2:
/usr/include/c++/4.8/bits/unique_ptr.h:273:7: error: declared here
unique_ptr(const unique_ptr&) = delete;
^
prog.cpp:63:6: error: initializing argument 1 of ‘void BinarySearchTree<T>::print(BinarySearchTree<T>::spTreeNode) const [with T = int; BinarySearchTree<T>::spTreeNode = std::unique_ptr<BinarySearchTree<int>::TreeNode, std::default_delete<BinarySearchTree<int>::TreeNode> >]’
void BinarySearchTree<T>::print(const spTreeNode node)const
^
unique_ptr
s不可分配,但可移动。我重新编写了您的示例,现在使用unique_ptr
。请注意,我使用std::move
是为了将内容从一个unique_ptr
移动到另一个。同样由于unique_ptr
是不可复制的,我在成员函数中通过引用而不是值传递unique_ptr
s:
#include <iostream>
#include <memory>
template<class T>
class BinarySearchTree{
struct TreeNode;
typedef std::unique_ptr<TreeNode> spTreeNode;
struct TreeNode{
T data;
spTreeNode left;
spTreeNode right;
TreeNode(const T & value):data(value),left(nullptr),right(nullptr){}
};
spTreeNode root;
bool insert(spTreeNode &node);
void print(const spTreeNode&) const ;
public:
BinarySearchTree();
void insert( const T & node);
void print()const;
};
template<class T>
BinarySearchTree<T>::BinarySearchTree():root(nullptr){}
template<class T>
void BinarySearchTree<T>::insert(const T & ref)
{
std::unique_ptr<TreeNode> node(new TreeNode(ref));
if (root == nullptr) {
root = std::move(node);
} else {
TreeNode* temp = root.get();
TreeNode* prev = root.get();
while (temp != nullptr) {
prev = temp;
if (temp->data < ref)
temp = temp->right.get();
else
temp = temp->left.get();
}
if (prev->data < ref)
prev->right = std::move(node);
else
prev->left = std::move(node);
}
}
template<class T>
void BinarySearchTree<T>::print()const
{
print(root);
}
template<class T>
void BinarySearchTree<T>::print(const std::unique_ptr<TreeNode> &node) const
{
if(node == nullptr) return;
print(node->left);
std::cout << node->data<< std::endl;
print(node->right);
}
int main()
{
BinarySearchTree<int> bst;
bst.insert(13);
bst.insert(3);
bst.insert(5);
bst.insert(31);
bst.print();
return 0;
}
现场演示
模板风格的错误总是很可怕,但不要惊慌!所有这些"删除函数的使用"都是关于你试图复制一个unique_ptr
,它的超能力来自于只能移动。跳到每一行,分析情况:
您是否希望转让指定对象的所有权?然后通过右值引用传递唯一指针,并将其移动到新的保持器。
// Take unique_ptr by rvalue reference
void TreeNode::setLeft(std::unique_ptr<TreeNode> &&node) {
// Move it in a member variable
left = std::move(node);
// Now it's ours !
}
你只是想介绍一下对方吗?使用对unique_ptr的常量左值引用,或从unique_ptr.get((.传递常量原始指针
// Take raw const pointer
bool isNodeLeft(TreeNode const *node) const {
// Look at it but don't disturb it
return node->value <= value;
}
一旦所有这些都解决了,您要么会有一个编译代码,要么会解决一些其他错误,要么我会更新这个答案。
注意:TreeNode *node = new TreeNode(ref);
在为异常安全大声疾呼。您应该使用make_unique(来自C++1y,或者自己制作(。
这是:
template <class T, class... Args>
std::unique_ptr<T> make_unique(Args&&... args) {
return unique_ptr<T>(new T(std::forward<Args>(args)...));
}