当shared_ptr时,unique_ptr

时间:2015-08-17 15:41:28

标签: c++ c++11 shared-ptr unique-ptr

我什么时候应该使用shared_ptr和unique_ptr?

例如,在此类而不是node *中应该是shared_ptr或unique_ptr。它取决于什么?

class node
{
private:
    node *parent;
    vector<node*> children;

    /*
     * txny
     * x - numer drzewa
     * y - numer wezla
     */
    string id;
    typeNode type; //0 - term, 1 - func

public:
    node(node* parent, string id, typeNode type);
    virtual ~node() {}

    void addChild(node* child);
    void setChildren(vector<node*> &children);
    node* getChild(int i);
    int getChildrenNumber();
    void setParent(node* parent);
    node* getParent();
    string getId();
    typeNode getType();
    void setId(string id);
}; 

编辑:

类树拥有节点对象。我必须写更多的文字因为不能保存更改。

class tree
{
private:
    vector <node*> nodes;
    int depth;
    int counterNodes;
    /*
     * pxty
     * x - numer populacji (generacji)
     * y - numer drzewa
     */
    string id;
private:
    node* root;
    node* parentGeneticPoint;
public:
    tree(int depth, string id);
    tree(int depth);
    ~tree();
public:
    void initialize(typeInit type);
    void showVector();
    void show();
    Mat run();
    tree* copy();
    tree* copySubtree(int subrootI);
    tree* copyWithoutSubtree(int subrootI);

};

3 个答案:

答案 0 :(得分:6)

对于此树结构,您应该为子项shared_ptr和父项weak_ptr

为什么?

  • shared_ptr允许其他对象也指向子节点(例如,如果你在某处指向子树的指针)。
  • weak_ptrshared_ptr类似,但并不取得所有权。因此,如果某个节点不再由其父节点或其他shared_ptr指向,则它将被销毁。如果它自己的孩子有一个shared_ptr,那么由于圆形参考,该对象永远不会被破坏。
如果只有一个对象负责指针及其删除,则应使用

unique_ptr。这尤其意味着您不应该制作指针的副本。但是,您可以转让其所有权。

编辑:其他信息

评论显示此事比这个答案更复杂。毕竟,有完整的书籍章节专门讨论这个主题;-)三个问题将帮助您选择正确的设计:谁拥有指向的对象?指针会被赋予外部词吗?你想对这些指针给出什么保证?

如果您希望其他对象(即节点结构外部)安全地指向您的节点(即您不希望节点在外部使用时消失),您需要{{1 }}。当没有shared_ptr引用它时,将删除节点。

如果相反,节点&#34;拥有&#34;它的子女并且对他们的毁灭负有唯一责任,shared_ptr可以选择去。 unique_ptr可用于获取(原始)指向节点的指针,但不保证它们将在以后保持有效。

答案 1 :(得分:3)

shared_ptr以正则表达式解决html解析问题的方式解决内存管理问题。

shared_ptr可以成为终身管理问题解决方案的一部分,但它绝不会,形成或形成随便使用的东西。很容易被错放&#34;指针或引用循环,shared_ptr。根据我的经验,使用shared_ptr作为内部私有实现细节,其中包含防护,不变量和公理,它们共同证明你不能形成循环,并且你有可能没有问题。

我使用shared_ptr的一半以上由一个拥有&#34;拥有&#34;指针,以及weak_ptr以外的其他观察者,当他们检查资源仍然存在时,除了狭窄的窗口外,还有理由认为shared_ptr不会在那个狭窄的窗口中死亡。

另一个很好的用途是当我有写时复制的情况时,我有一个几乎不可变的对象状态可以被复制(存储在shared_ptr<const T> pimpl中。当写操作发生时,如果我是唯一的用户,我将其转换为shared_ptr<T>并修改它。否则,我将其复制到shared_ptr<T>并修改它。然后我将其存储为{{1}在这两种情况下。

根据我的经验,简单地散布shared_ptr<const T>不可避免地导致泄漏和资源持续时间远远超过他们应该的时间。

另一方面,您应该使用shared_ptr。几乎在所有情况下,unique_ptrmake_unique都应该替换代码中的unique_ptrnew。真的,真的很难让delete出错,当你这么做时,通常是因为旧代码存在严重的泄密风险,或者你之前并不了解资源的管理方式。 / p>

在新的代码中,它是一个明智的选择。在旧代码中,如果您需要了解所涉及对象的生命周期,您必须学习足够的知识,无论如何都要将所有权放在unique_ptr中。最重要的例外是你正在做货物崇拜&#34;编程(修改一个你不会以类似系统中其他代码的方式理解的复杂系统,并希望它能够工作,因为其他代码工作)以这种方式管理资源是不可行的。还有一些其他例外,例如以复杂的方式管理自己的生命周期的对象。

使用unique_ptr管理非new资源非常困难,但我也觉得有价值。

有时你被迫unique_ptr将指针指向一个长C风格.release填充的调用链。

void*上也存在运行时开销,但shared_ptr使对象生命周期更难以理解的概念开销是避免使用它的真正原因。

shared_ptr可用于做奇特的事情,但无法解决您的问题,它是一个工具,作为综合资源管理系统的一部分,您可以用来制作您的解决方案有点简单。

shared_ptr上的运行时开销几乎为零:它与指针大小相同,只是在生命周期结束时调用unique_ptr

delete解决了整个资源管理问题。一旦你正确使用它们就会蒸发掉。

在您的具体示例中,我要将unique_ptr放在unique_ptr中,并在节点中保留原始指针。

或者,将tree保留在unique_ptr向量中,并在树中和父指针中保留原始指针。

在任何一种情况下,添加/删除节点的所有操作都应通过children(为目标获取节点参数),因为状态为treetree需要保持同步。

当我指出根node中的节点列表是个坏主意时,您表示有兴趣获取随机节点。

只需存储每个节点中的子项数。 (这需要在添加/修改/删除必须级联到根目录的子项时才能工作。)

添加:

tree

这得到了节点的第n个后代,假设node* node::nth_node( int n ) { if (n == 0) return this; --n; for( auto&& child:children ) { if (n < child->subtree_size) return child->nth_node(n); n -= child->subtree_size; } return nullptr; // n is too big } 是树subtree_size是一个多大的根(包括它自己,所以它永远不应该是node)。

要从0获取随机节点,请创建从tree0的随机数。即,如果root->subtree_sizeroot->subtree_size,则您的随机数为301

然后拨打2

答案 2 :(得分:2)

尽可能使用unique_ptr(谨防移动/放弃所有权),shared_ptr需要额外的内存和同步成本,此外,拥有资源的单一所有权更可取自设计观点。