When shared_ptr, when unique_ptr
When shared_ptr, when 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);
};
在这种树结构的情况下,您应该将shared_ptr
用于子节点,weak_ptr
用于父节点。
为什么?
-
shared_ptr
允许其他对象也指向子对象(例如,如果您在某处保留指向子树的指针)。 -
weak_ptr
与shared_ptr
相似,但不占有所有权。所以在这里,如果一个节点不再被它的父节点或其他shared_ptr
指向,它将被销毁。如果它自己的子对象具有shared_ptr
,则该对象永远不会因为循环引用而被销毁。
unique_ptr
。这特别意味着你不应该复制指针。但是你可以转让它的所有权。
编辑:附加信息
评论表明问题比这个答案要复杂得多。毕竟,有整整一本书的章节专门讨论这个话题;-)三个问题应该帮助你选择正确的设计:谁拥有指向的对象?会给外界一些提示吗?对于这些指针,你想给出什么保证?
如果您希望其他对象(即在节点结构之外)安全地指向您的节点(即您不希望节点在外部使用时消失),您将需要shared_ptr
。当一个节点不再被shared_ptr引用时,该节点将被删除。
如果相反,一个节点"拥有"它的子节点,并对它们的破坏负责,那么unique_ptr
可能是一个选择。unique_ptr::get()
可用于获取指向节点的(原始)指针,但不能保证它们在以后的时间内保持有效。
shared_ptr
以正则表达式解决html解析问题的方式解决内存管理问题。
shared_ptr
可以成为终身管理问题的解决方案的一部分,但它绝不是随意使用的东西。"放错地方"是非常容易的。指针,或引用循环,使用shared_ptr
。根据我的经验,使用shared_ptr
作为内部私有实现细节,其中包含保护、不变量和公理,它们共同证明不能形成循环,并且您有相当大的机会不会出现问题。
我使用shared_ptr
的一半以上是由一个"拥有"的位置组成的。指针,以及其他具有weak_ptr
s的观察者(除了在狭窄的窗口中检查资源是否仍然存在),再加上shared_ptr
不会在狭窄的窗口中死亡的理由。
另一个很好的使用块是当我有一个写时复制的情况,我有一个几乎不可变的对象状态,可以复制(存储在shared_ptr<const T> pimpl
. 19中)。当写操作发生时,如果我是唯一的用户,我将其转换为shared_ptr<T>
并对其进行修改。否则,我将其复制到shared_ptr<T>
中并进行修改。然后我将其存储为shared_ptr<const T>
。
根据我的经验,简单地分散shared_ptr
s不可避免地会导致泄漏和资源持续的时间远远超过应有的时间。
另一方面,应该只使用unique_ptr
。几乎在任何情况下,make_unique
和unique_ptr
都应该取代代码中的new
和delete
。让unique_ptr
出错是非常非常困难的,当你出错时,通常是因为旧代码有严重的泄漏风险,或者你不理解以前是如何管理资源的。
在新代码中,这是无需动脑筋的。在旧代码中,如果您需要了解所涉及的对象的生命周期,那么无论如何,您必须学习足够的知识才能将所有权放在unique_ptr
中。最大的例外是当你在做"货物崇拜"时。编程(修改一个你不理解的复杂系统,让它看起来像系统中的其他代码,并希望它能正常工作,因为其他代码正常工作)以这种方式管理资源是不可行的。也有一些其他的例外,比如对象以一种复杂的方式管理自己的生命周期。
用unique_ptr
管理非new
'd资源有点困难,但我也觉得值得。
有时你被迫将指针.release
放入一个长c风格的void*
填充的调用链中。
shared_ptr
也有运行时开销,但shared_ptr
的概念开销使对象生命周期更加难以理解,这是避免使用它的真正原因。
shared_ptr
可以用来做一些花哨的事情,但它并不能解决你的问题,它是一个工具,作为一个全面的资源管理系统的一部分,你可以使用它来使你的解决方案更简单。
unique_ptr
的运行时开销几乎为零:它与指针大小相同,并且在生命周期结束时只调用delete
。
unique_ptr
解决了整个资源管理问题。一旦你使用得当,它们就会蒸发。
在您的具体示例中,我要么将unique_ptr
s放在tree
中,并在节点中保留原始指针。
或者,将unique_ptr
s保留在children
向量中,原始指针保留在树和父指针中。
在任何一种情况下,所有添加/删除节点的操作都应该通过tree
(为目标获取节点参数),因为tree
和node
s的状态需要保持同步。
当我指出根节点tree
中的节点列表是一个坏主意时,您表示有兴趣获得一个随机节点。
只是在每个节点中存储子节点的数量。(这需要在添加/修改/删除必须级联到根的子节点时进行工作)。
添加:
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
}
这会得到节点的第n个后代,假设subtree_size
是node
的根树的大小(包括它自己,所以它不应该是0
)。
要从tree
中获得一个随机节点,在0
到root->subtree_size
之间创建一个随机数。例如,如果root->subtree_size
是3
,则您的随机数是0
, 1
或2
。
然后调用root->nth_node( that_random_number )
只要可能,使用unique_ptr
(但要注意移动/放弃所有权),shared_ptr
有额外的内存和同步成本,此外,从设计的角度来看,拥有一个资源的单一所有权位置是可取的。
- 为什么 std::unique 不调用 std::sort?
- CLANG 编译器 说:变量"PTR"可能未初始化
- 在以唯一ptr为值的C++映射中,动态内存何时会被销毁
- 将 ptr 传递给 ptr 到 A 作为参数传递给 A 的函数是不好的做法吗?
- 为共享 ptr 向量实现复制 c'tor?
- 字符和整数中 **(ptr+1) 的值差异
- C++:在不中断共享的情况下通过引用传递共享 PTR?
- 生成"unique"矩阵
- 如何将派生类从基 ptr 分配给 nlohmann::json
- 引用 std::shared:ptr 以避免引用计数
- 我对 std::unique(算法)C++有问题
- 为什么我不能在不进行任何转换的情况下将浮点数放入任何类型的 ptr 中?
- 在调用函数时,ptr** 和 ptr*& 之间是否有区别,或者首选C++?
- 另一种类型的智能ptr,比如具有弱refs的unique_ptr
- 尝试打印出 *ptr++ 的值,以了解它是如何工作的
- 如何控制共享 ptr 引用计数?
- std::shared_ptr::unique(),复制和线程安全
- 如何在C++03中用自定义谓词调用std::unique
- C++中的指针否定 (!ptr == NULL)
- C++14 unique_ptr并使用已删除的函数'std::unique-ptr' unique_ptr错误