4

好的,所以每个人都知道应该像瘟疫一样避免使用原始指针并更喜欢智能指针,但是这个建议在实现容器时是否适用?这就是我想要完成的:

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;
}

(在这个例子中这没什么大不了的,但我可以想象它怎么会成为一个问题)。我是否应该将这些问题作为强烈暗示容器应该使用良好的 old newdelete和 raw 指针来实现?仅仅为了避免编写析构函数似乎非常麻烦。

4

5 回答 5

7

如您所示,在实现容器时,我通常不使用智能指针。不能像瘟疫一样避免原始指针(恕我直言) 。当您想要强制执行内存所有权时,请使用智能指针。但通常在容器中,容器拥有构成数据结构的指针所指向的内存。

如果在你的设计中,一个AVLTreeNode唯一地拥有它的左右孩子并且你想用 来表达unique_ptr,那很好。但是,如果您希望它AVLTree拥有所有AVLTreeNodes,并且使用原始指针这样做,那同样有效(并且是我通常编码它的方式)。

相信我,我不是反智能指针。我是发明者unique_ptr。但这unique_ptr只是工具箱中的另一个工具。在工具箱中拥有好的智能指针并不是万能的,盲目地使用它们并不能代替精心设计。

更新以回复评论(评论框太小):

我经常使用原始指针(很少拥有)。我的编码风格的一个很好的样本存在于开源项目libc++中。可以在“浏览 SVN”链接下浏览源代码。

由于异常安全问题,即使通常的释放发生在析构函数之外,我更喜欢资源的每次分配都可以在某个析构函数中释放。当分配由单个指针拥有时,智能指针通常是工具箱中最方便的工具。当分配由比指针更大的东西(例如容器或类Employee)拥有时,原始指针通常是构成更大对象的数据结构的方便部分。

最重要的是,我永远不会在不知道哪个对象拥有该资源的情况下分配任何资源,无论是智能指针、容器还是其他任何东西。

于 2011-03-29T14:03:54.130 回答
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;
}

测试编译:https ://ideone.com/aUAHs

就个人而言,我一直在对树使用智能指针,即使我们唯一拥有的是std::auto_ptr

至于rotate_right,它可以通过几个调用来实现unique_ptr::swap

于 2011-03-29T10:40:01.387 回答
0

小修正:不应该像瘟疫一样避免使用原始指针(哎呀,不是每个人都知道这个事实),但应该尽可能避免手动内存管理(通过使用容器而不是动态数组或智能指针),所以在你的函数中,只需执行你的 unique_ptr 上的 get() 用于临时存储。

于 2011-03-29T10:54:18.687 回答
0

std::shared_ptr没有这些限制。特别是,多个shared_ptr实例可以引用同一个对象。

于 2011-03-29T11:06:29.573 回答
0

Herb Shutter 对在他的 GoTW 系列中不使用 shared_ptr 作为参数有非常明确的指导:

指南:不要将智能指针作为函数参数传递,除非您想使用或操作智能指针本身,例如共享或转让所有权。

还有这个...

准则:更喜欢按值、* 或 & 传递对象,而不是通过智能指针。

于 2016-12-20T08:10:38.757 回答