我什么时候应该使用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);
};
答案 0 :(得分:6)
对于此树结构,您应该为子项shared_ptr
和父项weak_ptr
。
为什么?
shared_ptr
允许其他对象也指向子节点(例如,如果你在某处指向子树的指针)。 weak_ptr
与shared_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_ptr
和make_unique
都应该替换代码中的unique_ptr
和new
。真的,真的很难让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
(为目标获取节点参数),因为状态为tree
和tree
需要保持同步。
当我指出根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
获取随机节点,请创建从tree
到0
的随机数。即,如果root->subtree_size
为root->subtree_size
,则您的随机数为3
,0
或1
。
然后拨打2
。
答案 2 :(得分:2)
尽可能使用unique_ptr
(谨防移动/放弃所有权),shared_ptr
需要额外的内存和同步成本,此外,拥有资源的单一所有权更可取自设计观点。