繁体   English   中英

删除C ++中的动态指针数组

[英]Deleting a dynamic array of pointers in C++

我有一个关于删除C ++中的动态指针数组的问题。 假设我们有以下情况:

int n;
scanf("%d", &n);
Node **array1 = new Node*[n];
/* ... */

其中,Node是预先定义的特定结构。 假设在使用new运算符分配后,我们更改了array1的内容(但我们不删除任何内容!)。 如果数组中可能存在重复的指针(不按线性顺序对它们进行排序或插入到集合中),则删除array1及其所有内容的正确方法是什么?

使用此分配:

Node **array1 = new Node*[n];

array1的内容是undefined 每个元素都是一个Node* ,并且由于内存尚未初始化,因此该值可以是任何值。

分配指针数组不会构造指向类的对象。

因此,无论将什么指针放入数组,它们指向的对象都需要在其他位置构造和销毁。

因此,回答您的问题,删除array1的正确方法是

delete[] array1;

但是,请注意, 这不会导致为每个Node*调用析构函数- 删除数组之前,应处理放入数组中的所有内容。

编辑:我对原始问题感到困惑,它在数组中提到“更改值”, 就好像在您的示例中分配的数组中一个有效值一样。

但是...据我所知,您以后想要跟踪要删除的指针,也许您可​​以为此目的创建另一个数组,其中每个指针仅存在一次。 因此,您有了上面当前拥有的数组,其中包含指向可能会重复使用的节点的指针,无论您出于何种目的使用它。 然后,您将拥有另一个数组来明确管理删除,每个指针仅出现一次。 pNewNode = new Node()之后pNewNode = new Node()设置诸如nodeCleanupArray[i] = pNewNode类的东西应该足够容易,然后您可以在线性时间内遍历该数组并delete每个元素。 (这意味着您不必费心检查array1中的元素,而是依靠nodeCleanupArray进行清理)

对于这种问题有很多解决方案,但是最明显的选择是将其更改为使用

std::vector< std::shared_ptr<Node> >

现在,您将拥有一个引用计数的指针,而无需编写任何代码,还有一个不需要知道其预定义大小的“数组”。

当然,您可以在Node内实现引用计数的对象,也可以在自己的容器对象中实现相同的目的,但这似乎带来了额外的麻烦,几乎没有好处。

尝试标记和清除:)您正在尝试实施托管环境。

这是一个例子:

struct Node
{
... 
    bool marked;

    Node() : marked(false)
    {}
};

现在删除:

void do_delete(Node **data, size_t n)
{
    size_t uniq = 0;
    Node **temp = new Node*[n];

    for (size_t i = 0; i < n; i++)
    {
        if (data[i] && !data[i]->marked)
        {
            data[i]->marked = true;
            temp[uniq++] = data[i];
        }
    }

    for (i = 0; i < uniq; ++i)
    {
        delete temp[i];
    } 

    delete[] temp;
    delete[] data;
}

我这样做的方法是有一个引用计数器,并有一个Node :: deref方法,当引用计数为0时,它将删除节点本身。当遍历节点列表时,调用node-> deref实际上不会删除该节点。对象,直到数组中的最后一个Node引用为止。

删除array1及其所有内容的正确方法是什么

您显示一个分配; new Node*[n] 此分配使程序有责任调用delete [] whatever_the_return_value_was 这仅与删除该分配有关,而不与删除“其所有内容”有关。 如果您的程序执行其他分配,则程序需要安排这些职责也要进行处理。

如果数组中可能存在重复的指针

那么delete与当前分配不相关的指针值将是不确定的行为,因此您必须避免多次删除同一指针值。 这不是一个单一正确方法的问题,而是编程实践,设计等问题。

通常,C ++使用RAII来自动处理这些内容,而不是尝试手动执行您想要的操作,因为手动执行确实很难正确。 在这里使用RAII的一种方法是拥有“拥有”节点的第二个对象。 然后,您的array1将简单地使用原始指针作为“非所有”指针。 然后,通过使拥有节点的对象超出范围或以其他方式销毁,可以删除所有节点。

{
  // object that handles the ownership of Node objects.
  std::vector<std::unique_ptr<Node>> node_owner;

  // your array1 object that may hold repeated pointer values.
  std::vector<Node*> array1;

  node_owner.emplace_back(new Node); // create new nodes

  array1.push_back(node_owner.back().get()); // put nodes in the array
  array1.push_back(node_owner.back().get()); // with possible duplicates

  // array1 gets destroyed, but it's contents do not, so the repeated pointers don't matter
  // node_owner gets destroyed and destroys all its Nodes. There are no duplicates to cause problems.
}

而且破坏确实发生在线性时间内。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM