2011-03-29 58 views
2

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

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

(在这个例子中这不是一个大问题,但我可以想象它会如何成为一个问题)。我是否应该将这些问题看作是强烈暗示容器应该使用旧的newdelete和原始指针来实现的问题?避免编写析构函数似乎非常麻烦。

+0

除了用传统的包含警卫替换一次编译指示,我已经复制了你的代码,并且不使用clang/libC++复制你的错误。我建议预处理driver.cpp,检查一下,看看你是否看到'unique_ptr'。您看到的行为可能与'unique_ptr'无关,例如不包括''的C++ 11版本。 – 2011-03-29 15:43:41

回答

5

我在实现容器时通常不会使用智能指针。原始指针(imho)是而不是要避免像瘟疫一样。当你想强制内存所有权时使用智能指针。但通常在容器中,容器拥有组成数据结构的指针所指向的内存。

如果在您的设计中,AVLTreeNode独有地拥有其左侧和右侧的孩子,并且您想用unique_ptr来表达,那很好。但是如果你更喜欢AVLTree拥有所有的AVLTreeNode s,并且使用原始指针进行处理,那么这也是一样有效的(并且是我通常编写的方式)。

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

更新回应发表评论(评论框太小):

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

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

最重要的是,我从不分配任何资源,而不必知道对象拥有哪个资源,无论是智能指针,容器还是其他任何资源。

+0

有趣。除了与C代码接口之外,还有哪些场合你更喜欢指向智能指针的原始指针? – jeffythedragonslayer 2011-03-30 22:19:04

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

+0

......很奇怪。 VC++编译你刚刚提供的内容,但拒绝了我的实现。我编辑了这个问题来包含我的代码,为什么它不编译的帮助将不胜感激。 – jeffythedragonslayer 2011-03-29 15:29:48

+0

@da_code_monkey VC++的东西。您的完整示例使用gcc 4.5.2进行编译,但只有在AVLTree a之前在'main'的开头处添加'AVLTreeNode dummy;'才会在VC++ 2010 EE上编译; – Cubbi 2011-03-29 15:48:18

0

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

0

std::shared_ptr没有这些限制。尤其是,多个shared_ptr -instances可以引用同一个对象。

0

香草快门大约有没有使用his GoTW series的shared_ptr作为参数非常明确的指引:

准则:不要通过智能指针,除非 要使用或操作的智能指针本身的函数参数,如以 分享或转让所有权。

这...

准则:按值传递不想对象,*或&,而不是由智能 指针。