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

时间:2013-03-14 20:04:29

标签: c++ pointers dynamic-memory-allocation

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

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

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

5 个答案:

答案 0 :(得分:3)

使用此分配:

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

array1的内容是 undefined 。每个元素都是Node*,因为内存未初始化,所以值可以是任何值。

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

因此,无论您将哪些指针放入数组中,它们指向的对象都需要在其他地方构建和销毁。

所以要回答你的问题,删除array1的正确方法是

delete[] array1;

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

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

但是......现在我明白你想要跟踪以后删除的指针,也许你可以为此目的创建另一个数组,其中每个指针只存在一次。因此,您拥有上面的数组,其中包含可能重复的节点的指针,无论您使用它的目的是什么。然后你有另一个数组用于管理删除的明确目的,其中每个指针只出现一次。在nodeCleanupArray[i] = pNewNode之后设置像pNewNode = new Node()这样的东西应该很容易,然后你可以在线性时间和delete每个元素中遍历该数组。 (这意味着你不会费心检查array1中的元素,你需要依赖nodeCleanupArray进行清理)

答案 1 :(得分:1)

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

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

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

您当然可以在Node或您自己的容器对象中实现引用计数对象来执行相同的操作,但这似乎是额外的麻烦,几乎没有任何好处。

答案 2 :(得分:0)

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

以下是一个例子:

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;
}

答案 3 :(得分:0)

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

答案 4 :(得分:0)

  

删除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.
}

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