我正在实现一棵树,每个节点内部都有Node **供儿子使用:
class Node {
string word;
Node* father;
Node** sons;
int sonsNum;
....
}
对于插入新的儿子,我很想找到一种方法,而不是制作Node *的new []数组并删除旧的(我不能使用列表,我已整治...)。但是当使用delete []删除旧的Node **时,即使我将指针保存在另一个tmp数组中,其值也将消失! (甚至Node destrucor是空的!为什么?)。因此,如果我使用shared_ptr,我认为它将解决该问题,是否可以在没有shared_ptr的情况下做到这一点?
void insertSon(Node* sn) {
sn->father=this;
Node** tmpSons = sons; //should be shared_ptr? but I dont want that
if(sons)
//delete[](sons); // after this line, tmpSons has garbage!
sons = new Node*[sonsNum+1];
for(int i=0 ; i<sonsNum ; i++) {
sons[i]=tmpSons[i];
}
sons[sonsNum]=sn;
sonsNum++;
}
编辑:
抱歉忘记说我想要节点内的真实值,所以我无法复制。 (此代码中的字符串仅用于示例...它是真实的另一个对象。)
编辑:
解:
void insertSon(Node* sn) {
sn->father=this;
Node** tmpSons = new Node*[sonsNum];
for(int i=0 ; i<sonsNum ; i++) {
tmpSons[i]=sons[i];
}
if(sons)
delete[](sons);
sons = new Node*[sonsNum+1];
for(int i=0 ; i<sonsNum ; i++) {
sons[i]=tmpSons[i];
}
sons[sonsNum]=sn;
sonsNum++;
delete[](tmpSons);
}
最佳答案
Node** tmpSons = sons; //should be shared_ptr? but I dont want that
if(sons)
//delete[](sons); // after this line, tmpSons has garbage!
是的,这很正常-
tmpSons
的内容将指向与sons
相同的内存,并且您将使用operator delete[]
释放其内容,因此该内容将失效。无需涉及引用计数即可解决此类问题。只需分配一个新数组(不触摸
sons
),将sons
的内容复制到更大的新数组中,然后释放sons
的内存,并使sons
指向新块。关键是在完成将sons
的内容复制到新数组之前,不要释放它的内容。就像您不想将要复制的CD扔掉一样,直到复制完之后(您的原始版本有点在复制完成之前就把它扔掉了)。像这样:void insertSon(Node* sn) {
sn->father = this;
// Create a new array and copy the old data.
Node** new_sons = new Node*[sonsNum+1];
for(int i=0; i<sonsNum; i++)
new_sons[i] = sons[i];
new_sons[sonsNum++] = sn;
// Delete old data.
delete[] sons;
// Point to the new data.
sons = new_sons;
}
在开始担心异常安全之类的事情之前,这应该可以阻止您,这时您可能确实希望避免过多地依赖这些手动内存管理技术,而使用更多符合RAII的对象。
视觉细分
这是视觉故障。首先,我们从
sons
指针开始,该指针指向一个存储块,其中包含一些“父亲”的“儿子”(节点系统的所有父权命名约定,顺便说一句)。然后,我们分配一个新的,稍大的内存块,该内存块将由
new_sons
指向:Node** new_sons = new Node*[sonsNum+1];
接下来,我们将以前的子项复制到新数组中。
for(int i=0; i<sonsNum; i++)
new_sons[i] = sons[i];
...并添加我们的新条目。
new_sons[sonsNum++] = sn;
现在我们有了副本,我们可以丢弃旧数据。
// Delete old data.
delete[] sons;
...最后但并非最不重要的一点,我们可以使
sons
指向新数据。然后new_sons
将超出范围,并且指针也将被销毁(不是指针指向的东西,只是指针),我们最终将得到所需的信息(sons
现在指向一个新的数组,入口大一个,同时添加了旧条目和新条目)。// Point to the new data.
sons = new_sons;
...您就完成了。