[英]Implementing Containers using Smart Pointers
好吧,所以每个人都知道应该像瘟疫一样避免使用原始指针并选择智能指针,但是在实现容器时这个建议是否适用? 这就是我想要完成的事情:
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
和raw指针实现容器? 为避免编写析构函数,似乎非常麻烦。
在显示容器时,我通常不会使用智能指针。 原始指针(恕我直言) 不被避免像瘟疫。 如果要强制执行内存所有权,请使用智能指针。 但通常在容器中,容器拥有构成数据结构的指针所指向的内存。
如果在您的设计中, AVLTreeNode
唯一拥有其左右子项,并且您想用unique_ptr
表示,那很好。 但是如果你更希望AVLTree
拥有所有AVLTreeNode
,并且使用原始指针,那就是有效的(这是我通常编码它的方式)。
相信我,我不是反智能指针。 我是发明了unique_ptr
。 但unique_ptr
只是工具箱中的另一个工具。 在工具箱中拥有良好的智能指针并不是万灵药,盲目地使用它们并不能代替精心设计。
更新以回复评论(评论框太小):
我经常使用原始指针(很少拥有)。 我的编码风格的一个很好的样本存在于开源项目libc ++中 。 可以在“浏览SVN”链接下浏览源。
我更喜欢资源的每个分配都可以在某个地方的析构函数中释放,因为异常安全问题,即使通常的解除分配发生在析构函数之外。 当分配由单个指针拥有时,智能指针通常是工具箱中最方便的工具。 当分配由大于指针的东西(例如容器或类Employee
)拥有时,原始指针通常是组成较大对象的数据结构的便利部分。
最重要的是,我从不分配任何资源而不知道哪个对象拥有该资源,无论是智能指针,容器还是其他什么。
您提供的代码编译没有任何问题
#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
的几次调用来实现
Herb Shutter对于不在他的GoTW系列中使用shared_ptr作为参数有非常明确的指导:
准则:除非您想使用或操纵智能指针本身,例如共享或转移所有权,否则不要将智能指针作为函数参数传递。
和这个...
指南:首选按值,*或&传递对象,而不是通过智能指针传递对象。
小修正:不应该像瘟疫那样避免原始指针(哎呀,不是每个人都知道这个事实),但是应该尽可能避免手动内存管理(通过使用容器而不是动态数组或智能指针),所以在你的函数中,只需做您的unique_ptr上的get()用于临时存储。
std::shared_ptr
没有这些限制。 特别是,多个shared_ptr
-instances可以引用同一个对象。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.