简体   繁体   English

使用智能指针实现容器

[英]Implementing Containers using Smart Pointers

Ok, so everyone knows that raw pointers should be avoided like the plague and to prefer smart pointers, but does this advice apply when implementing a container? 好吧,所以每个人都知道应该像瘟疫一样避免使用原始指针并选择智能指针,但是在实现容器时这个建议是否适用? This is what I am trying to accomplish: 这就是我想要完成的事情:

template<typename T> class AVLTreeNode {
public:
    T data;
    unique_ptr<AVLTreeNode<T>> left, right;
    int height;
}

Unique_ptr can make container functions more cumbersome to write because I can't have multiple raw pointers temporarily pointing to the same object in a way that is elegant. Unique_ptr可以使容器函数编写起来更麻烦,因为我不能让多个原始指针以优雅的方式临时指向同一个对象。 For example: 例如:

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

(It's not a big deal in this example but I can imagine how it could become a problem). (在这个例子中,这不是什么大不了的事,但我可以想象它会如何成为一个问题)。 Should I take problems like these as a strong hint that containers should be implemented with good old new , delete , and raw pointers? 我是否应该将这些问题作为一个强烈暗示,即应该使用旧的newdelete和raw指针实现容器? It seems like awfully a lot of trouble just to avoid writing a destructor. 为避免编写析构函数,似乎非常麻烦。

I do not usually use smart pointers when implementing containers as you show. 在显示容器时,我通常不会使用智能指针。 Raw pointers (imho) are not to be avoided like the plague. 原始指针(恕我直言) 被避免像瘟疫。 Use a smart pointer when you want to enforce memory ownership. 如果要强制执行内存所有权,请使用智能指针。 But typically in a container, the container owns the memory pointed to by the pointers making up the data structure. 但通常在容器中,容器拥有构成数据结构的指针所指向的内存。

If in your design, an AVLTreeNode uniquely owns its left and right children and you want to express that with unique_ptr , that's fine. 如果在您的设计中, AVLTreeNode唯一拥有其左右子项,并且您想用unique_ptr表示,那很好。 But if you would prefer that AVLTree owns all AVLTreeNode s, and does so with raw pointers, that is just as valid (and is the way I usually code it). 但是如果你更希望AVLTree拥有所有AVLTreeNode ,并且使用原始指针,那就是有效的(这是我通常编码它的方式)。

Trust me, I'm not anti-smart-pointer. 相信我,我不是反智能指针。 I am the one who invented unique_ptr . 我是发明了unique_ptr But unique_ptr is just another tool in the tool box. unique_ptr只是工具箱中的另一个工具。 Having good smart pointers in the tool box is not a cure-all, and using them blindly for everything is not a substitute for careful design. 在工具箱中拥有良好的智能指针并不是万灵药,盲目地​​使用它们并不能代替精心设计。

Update to respond to comment (comment box was too small): 更新以回复评论(评论框太小):

I use raw pointers a lot (which are rarely owning). 我经常使用原始指针(很少拥有)。 A good sampling of my coding style exists in the open source project libc++ . 我的编码风格的一个很好的样本存在于开源项目libc ++中 One can browse the source under the "Browse SVN" link. 可以在“浏览SVN”链接下浏览源。

I prefer that every allocation of a resource be deallocate-able in a destructor somewhere, because of exception safety concerns, even if the usual deallocation happens outside of a destructor. 我更喜欢资源的每个分配都可以在某个地方的析构函数中释放,因为异常安全问题,即使通常的解除分配发生在析构函数之外。 When the allocation is owned by a single pointer, a smart pointer is typically the most convenient tool in the tool box. 当分配由单个指针拥有时,智能指针通常是工具箱中最方便的工具。 When the allocation is owned by something larger than a pointer (eg a container, or a class Employee ), raw pointers are often a convenient part of the data structure composing the larger object. 当分配由大于指针的东西(例如容器或类Employee )拥有时,原始指针通常是组成较大对象的数据结构的便利部分。

The most important thing is that I never allocate any resource without knowing what object owns that resource, be it smart pointer, container, or whatever. 最重要的是,我从不分配任何资源而不知道哪个对象拥有该资源,无论是智能指针,容器还是其他什么。

The code you presented compiles with no problems 您提供的代码编译没有任何问题

#include <memory>
template<typename T> class AVLTreeNode {
public:
    T data;
    std::unique_ptr<AVLTreeNode<T>> left, right;
    int height;
};
int main()
{
    AVLTreeNode<int> node;
}

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

Personally, I've been using smart pointers for trees even when the only thing we had was std::auto_ptr 就个人而言,我一直在使用智能指针树,即使我们唯一的东西是std::auto_ptr

As for rotate_right, it could be implemented with a couple calls to unique_ptr::swap 至于rotate_right,它可以通过对unique_ptr::swap的几次调用来实现

Herb Shutter has very clear guideline about not using shared_ptr as parameters in his GoTW series : Herb Shutter对于不在他的GoTW系列中使用shared_ptr作为参数有非常明确的指导:

Guideline: Don't pass a smart pointer as a function parameter unless you want to use or manipulate the smart pointer itself, such as to share or transfer ownership. 准则:除非您想使用或操纵智能指针本身,例如共享或转移所有权,否则不要将智能指针作为函数参数传递。

and this... 和这个...

Guideline: Prefer passing objects by value, *, or &, not by smart pointer. 指南:首选按值,*或&传递对象,而不是通过智能指针传递对象。

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

std::shared_ptr does not have these restrictions. std::shared_ptr没有这些限制。 Especially, multiple shared_ptr -instances can reference the same object. 特别是,多个shared_ptr -instances可以引用同一个对象。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM