好的,所以每个人都知道应该像瘟疫那样避免使用原始指针并选择智能指针,但是在实现容器时这个建议是否适用?这就是我想要实现的目标:
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
和原始指针来实现?为避免编写析构函数,似乎非常麻烦。
答案 0 :(得分:6)
在显示容器时,我通常不会使用智能指针。原始指针(imho)像瘟疫一样可以避免 。如果要强制执行内存所有权,请使用智能指针。但通常在容器中,容器拥有构成数据结构的指针所指向的内存。
如果在您的设计中,AVLTreeNode
唯一拥有其左右儿童并且您希望使用unique_ptr
来表达,那就没问题了。但是如果你希望AVLTree
拥有所有AVLTreeNode
s,并且使用原始指针,那就是有效的(这通常是我编码的方式)。
相信我,我不是反智能指针。我是发明unique_ptr
的人。但unique_ptr
只是工具箱中的另一个工具。在工具箱中拥有良好的智能指针并不是万灵药,盲目地使用它们并不能代替精心设计。
更新以回复评论(评论框太小):
我经常使用原始指针(很少拥有)。开源项目libc++中存在一个很好的编码样式。可以在“浏览SVN”链接下浏览源。
我更喜欢资源的每个分配都可以在某个地方的析构函数中解除分配,因为异常安全问题,即使通常的解除分配发生在析构函数之外。当分配由单个指针拥有时,智能指针通常是工具箱中最方便的工具。当分配由大于指针的东西(例如容器或类Employee
)拥有时,原始指针通常是组成较大对象的数据结构的一个方便部分。
最重要的是,我从不分配任何资源而不知道哪个对象拥有该资源,无论是智能指针,容器还是其他什么。
答案 1 :(得分:3)
您提供的代码编译没有任何问题
#include <memory>
template<typename T> class AVLTreeNode {
public:
T data;
std::unique_ptr<AVLTreeNode<T>> left, right;
int height;
};
int main()
{
AVLTreeNode<int> node;
}
就个人而言,即使我们唯一拥有的是std::auto_ptr
至于rotate_right,可以通过几次调用[{1}}
来实现答案 2 :(得分:0)
小修正:不应该像瘟疫一样避免原始指针(哎呀,不是每个人都知道这个事实),但应尽可能避免手动内存管理(通过使用容器而不是动态数组或智能指针),所以在你的功能中,只需在您的unique_ptr上执行get()以进行临时存储。
答案 3 :(得分:0)
std::shared_ptr
没有这些限制。特别是,多个shared_ptr
- 实例可以引用同一个对象。
答案 4 :(得分:0)
Herb Shutter有非常明确的指导原则,即不使用shared_ptr作为his GoTW series中的参数:
指南:除非将智能指针作为函数参数传递 你想使用或操纵智能指针本身,如 分享或转让所有权。
这......
指南:首选按值,*或&amp;而不是智能传递对象 指针。