简体   繁体   English

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

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

I have a question concerning deleting a dynamic array of pointers in C++. 我有一个关于删除C ++中的动态指针数组的问题。 Let's imagine that we have a following situation: 假设我们有以下情况:

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

where Node is a certain structure defined beforehand. 其中,Node是预先定义的特定结构。 Suppose that after allocation with the new operator, we change the content of the array1 (but we do not delete anything!). 假设在使用new运算符分配后,我们更改了array1的内容(但我们不删除任何内容!)。 What is the proper way to delete the array1 and all its content if there is a possibility of repeated pointers in the array (without sorting them or inserting into the set, in linear time)? 如果数组中可能存在重复的指针(不按线性顺序对它们进行排序或插入到集合中),则删除array1及其所有内容的正确方法是什么?

Using this allocation: 使用此分配:

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

The contents of array1 are undefined . array1的内容是undefined Each element is a Node* , and because the memory is uninitialized, the value could be anything. 每个元素都是一个Node* ,并且由于内存尚未初始化,因此该值可以是任何值。

Allocating an array of pointers does not construct objects of the pointed-to class. 分配指针数组不会构造指向类的对象。

So whatever pointers you put into the array, the objects they point to need to be constructed and destructed elsewhere. 因此,无论将什么指针放入数组,它们指向的对象都需要在其他位置构造和销毁。

So to answer your question, the proper way to delete array1 is 因此,回答您的问题,删除array1的正确方法是

delete[] array1;

However, note that this will not result in destructors being called for each Node* - you should deal with whatever you put into the array before you delete the array. 但是,请注意, 这不会导致为每个Node*调用析构函数- 删除数组之前,应处理放入数组中的所有内容。

EDIT: I was confused by the original question, which mentioned "change the value" in the array, as if there was a valid value in the array as allocated in your example. 编辑:我对原始问题感到困惑,它在数组中提到“更改值”, 就好像在您的示例中分配的数组中一个有效值一样。

BUT... now that I understand you want to keep track of the pointers for deletion later, perhaps you can just create another array for that purpose where each pointer exists only once. 但是...据我所知,您以后想要跟踪要删除的指针,也许您可​​以为此目的创建另一个数组,其中每个指针仅存在一次。 So you have the array you currently have above, which contains pointers to nodes that might be repeated, for whatever purpose you're using it. 因此,您有了上面当前拥有的数组,其中包含指向可能会重复使用的节点的指针,无论您出于何种目的使用它。 Then you have another array for the express purpose of managing the deletion, where each pointer occurs only once. 然后,您将拥有另一个数组来明确管理删除,每个指针仅出现一次。 It should be easy enough to set something like nodeCleanupArray[i] = pNewNode right after pNewNode = new Node() , then you can blast through that array in linear time and delete each element. pNewNode = new Node()之后pNewNode = new Node()设置诸如nodeCleanupArray[i] = pNewNode类的东西应该足够容易,然后您可以在线性时间内遍历该数组并delete每个元素。 (Which means you wouldn't bother inspecting the elements in array1, you'd rely on nodeCleanupArray for the cleanup) (这意味着您不必费心检查array1中的元素,而是依靠nodeCleanupArray进行清理)

There are MANY solutions to this sort of problem, but the most obvious choice would be to change it to use 对于这种问题有很多解决方案,但是最明显的选择是将其更改为使用

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

Now you will have a reference counted pointer without writing any code, and an "array" that doesn't need to know it's predefined size. 现在,您将拥有一个引用计数的指针,而无需编写任何代码,还有一个不需要知道其预定义大小的“数组”。

You can of course implement a reference counted object within Node , or your own container object to do the same thing, but that seems like extra hassle for little or no benefit. 当然,您可以在Node内实现引用计数的对象,也可以在自己的容器对象中实现相同的目的,但这似乎带来了额外的麻烦,几乎没有好处。

Try mark and sweep :) You are trying to implement a managed environment. 尝试标记和清除:)您正在尝试实施托管环境。

Here is an example: 这是一个例子:

struct Node
{
... 
    bool marked;

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

Now delete: 现在删除:

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引用为止。

What is the proper way to delete the array1 and all its content 删除array1及其所有内容的正确方法是什么

You show a single allocation; 您显示一个分配; new Node*[n] . new Node*[n] This allocation confers on the program the responsibility to call delete [] whatever_the_return_value_was . 此分配使程序有责任调用delete [] whatever_the_return_value_was This is only about deleting that one allocation and not about deleting 'all its content'. 这仅与删除该分配有关,而不与删除“其所有内容”有关。 If your program performs other allocations then the program needs to arrange for those responsibilities to be handled as well. 如果您的程序执行其他分配,则程序需要安排这些职责也要进行处理。

if there is a possibility of repeated pointers in the array 如果数组中可能存在重复的指针

Well it would be undefined behavior to delete a pointer value that is not associated with any current allocation, so you have to avoid deleting the same pointer value more than once. 那么delete与当前分配不相关的指针值将是不确定的行为,因此您必须避免多次删除同一指针值。 This is not an issue of there being a single correct way, but an issue of programming practices, design, etc. 这不是一个单一正确方法的问题,而是编程实践,设计等问题。

Typically C++ uses RAII to handle this stuff automatically instead of trying to do what you want by hand, because doing it by hand is really hard to get right. 通常,C ++使用RAII来自动处理这些内容,而不是尝试手动执行您想要的操作,因为手动执行确实很难正确。 One way to use RAII here would be to have a second object that 'owns' the Nodes. 在这里使用RAII的一种方法是拥有“拥有”节点的第二个对象。 Your array1 would then simply use raw pointers as 'non-owning' pointers. 然后,您的array1将简单地使用原始指针作为“非所有”指针。 Deleting all the Nodes then would be done by letting the Node owning object go out of scope or otherwise be destroyed. 然后,通过使拥有节点的对象超出范围或以其他方式销毁,可以删除所有节点。

{
  // 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.
}

And the destruction does occur in linear time. 而且破坏确实发生在线性时间内。

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

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