我正在实现一棵树,每个节点内部都有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指针开始,该指针指向一个存储块,其中包含一些“父亲”的“儿子”(节点系统的所有父权命名约定,顺便说一句)。

c&#43;&#43; - 如何在不使用shared_ptr的情况下不删除指针的值-LMLPHP

然后,我们分配一个新的,稍大的内存块,该内存块将由new_sons指向:
Node** new_sons = new Node*[sonsNum+1];

c&#43;&#43; - 如何在不使用shared_ptr的情况下不删除指针的值-LMLPHP

接下来,我们将以前的子项复制到新数组中。
for(int i=0; i<sonsNum; i++)
    new_sons[i] = sons[i];

c&#43;&#43; - 如何在不使用shared_ptr的情况下不删除指针的值-LMLPHP

...并添加我们的新条目。
new_sons[sonsNum++] = sn;

c&#43;&#43; - 如何在不使用shared_ptr的情况下不删除指针的值-LMLPHP

现在我们有了副本,我们可以丢弃旧数据。
// Delete old data.
delete[] sons;

c&#43;&#43; - 如何在不使用shared_ptr的情况下不删除指针的值-LMLPHP

...最后但并非最不重要的一点,我们可以使sons指向新数据。然后new_sons将超出范围,并且指针也将被销毁(不是指针指向的东西,只是指针),我们最终将得到所需的信息(sons现在指向一个新的数组,入口大一个,同时添加了旧条目和新条目)。
// Point to the new data.
sons = new_sons;

c&#43;&#43; - 如何在不使用shared_ptr的情况下不删除指针的值-LMLPHP

...您就完成了。

10-06 02:50