C++ 指针数组:删除还是删除 []?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2814188/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 11:09:57  来源:igfitidea点击:

C++ Array of pointers: delete or delete []?

c++arrayspointersdelete-operator

提问by Jasper

Cosider the following code:

考虑以下代码:

class Foo
{
    Monster* monsters[6];

    Foo()
    {
        for (int i = 0; i < 6; i++)
        {
            monsters[i] = new Monster();
        }
    }

    virtual ~Foo();
}

What is the correct destructor?

什么是正确的析构函数?

this:

这个:

Foo::~Foo()
{
    delete [] monsters;
}

or this:

或这个:

Foo::~Foo()
{
    for (int i = 0; i < 6; i++)
    {
        delete monsters[i];
    }
}

I currently have the uppermost constructor and everything is working okey, but of course I cannot see if it happens to be leaking...

我目前有最上面的构造函数,一切正常,但当然我看不到它是否恰好在泄漏......

Personally, I think the second version is much more logical considering what I am doing. Anyway, what is the "proper" way to do this?

就我个人而言,考虑到我在做什么,我认为第二个版本更合乎逻辑。无论如何,这样做的“正确”方法是什么?

回答by CB Bailey

delete[] monsters;

delete[] monsters;

Is incorrect because monstersisn't a pointer to a dynamically allocated array, it isan array of pointers. As a class member it will be destroyed automatically when the class instance is destroyed.

不正确,因为monsters不是一个指向一个动态分配的数组,它一个指针数组。作为类成员,它会在类实例被销毁时自动销毁。

Your other implementation is the correct one as the pointers in the array do point to dynamically allocated Monsterobjects.

您的另一个实现是正确的,因为数组中的指针确实指向动态分配的Monster对象。

Note that with your current memory allocation strategy you probably want to declare your own copy constructor and copy-assignment operator so that unintentional copying doesn't cause double deletes. (If you you want to prevent copying you could declare them as private and not actually implement them.)

请注意,使用当前的内存分配策略,您可能希望声明自己的复制构造函数和复制赋值运算符,以便无意复制不会导致双重删除。(如果你想防止复制,你可以将它们声明为私有而不实际实现它们。)

回答by Kirill V. Lyadvinsky

For newyou should use delete. For new[]use delete[]. Your second variant is correct.

因为new你应该使用delete. 供new[]使用delete[]。您的第二个变体是正确的。

回答by Jerry Coffin

The second one is correct under the circumstances (well, the least wrong, anyway).

在这种情况下,第二个是正确的(好吧,至少是错误的,无论如何)。

Edit: "least wrong", as in the original code shows no good reason to be using newor deletein the first place, so you should probably just use:

编辑:“最少错误”,因为在原始代码中没有显示使用newdelete首先的充分理由,因此您可能应该使用:

std::vector<Monster> monsters;

The result will be simpler code and cleaner separation of responsibilities.

结果将是更简单的代码和更清晰的职责分离。

回答by shai vashdi

To simplify the answare let's look on the following code:

为了简化 answare,让我们看一下以下代码:

#include "stdafx.h"
#include <iostream>
using namespace std;

class A
{
private:
    int m_id;
    static int count;
public:
    A() {count++; m_id = count;}
    A(int id) { m_id = id; }
    ~A() {cout<< "Destructor A "   <<m_id<<endl; }
};

int A::count = 0;

void f1()
{   
    A* arr = new A[10];
    //delete operate only one constructor, and crash!
    delete arr;
    //delete[] arr;
}

int main()
{
    f1();
    system("PAUSE");
    return 0;
}

The output is: Destructor A 1 and then it's crashing (Expression: _BLOCK_TYPE_IS_VALID(phead- nBlockUse)).

输出是:析构函数 A 1 然后它崩溃了(表达式:_BLOCK_TYPE_IS_VALID(phead- nBlockUse))。

We need to use: delete[] arr; becuse it's delete the whole array and not just one cell!

我们需要使用:delete[] arr; 因为它删除了整个数组而不仅仅是一个单元格!

try to use delete[] arr; the output is: Destructor A 10 Destructor A 9 Destructor A 8 Destructor A 7 Destructor A 6 Destructor A 5 Destructor A 4 Destructor A 3 Destructor A 2 Destructor A 1

尝试使用 delete[] arr; 输出为: 析构函数 A 10 析构函数 A 9 析构函数 A 8 析构函数 A 7 析构函数 A 6 析构函数 A 5 析构函数 A 4 析构函数 A 3 析构函数 A 2 析构函数 A 1

The same principle is for an array of pointers:

相同的原理适用于指针数组:

void f2()
{
    A** arr = new A*[10];
    for(int i = 0; i < 10; i++)
    {
        arr[i] = new A(i);
    }
    for(int i = 0; i < 10; i++)
    {
        delete arr[i];//delete the A object allocations.
    }

    delete[] arr;//delete the array of pointers
}

if we'll use delete arr instead of delete[] arr. it will not delete the whole pointers in the array => memory leak of pointer objects!

如果我们将使用 delete arr 而不是 delete[] arr。它不会删除数组中的整个指针 => 指针对象的内存泄漏!

回答by fredoverflow

delete[] monstersis definitely wrong. My heap debugger shows the following output:

delete[] monsters肯定是错的。我的堆调试器显示以下输出:

allocated non-array memory at 0x3e38f0 (20 bytes)
allocated non-array memory at 0x3e3920 (20 bytes)
allocated non-array memory at 0x3e3950 (20 bytes)
allocated non-array memory at 0x3e3980 (20 bytes)
allocated non-array memory at 0x3e39b0 (20 bytes)
allocated non-array memory at 0x3e39e0 (20 bytes)
releasing     array memory at 0x22ff38

As you can see, you are trying to release with the wrong form of delete (non-array vs. array), and the pointer 0x22ff38 has never been returned by a call to new. The second version shows the correct output:

如您所见,您试图以错误的删除形式(非数组与数组)进行释放,并且从未通过调用 new 返回指针 0x22ff38。第二个版本显示了正确的输出:

[allocations omitted for brevity]
releasing non-array memory at 0x3e38f0
releasing non-array memory at 0x3e3920
releasing non-array memory at 0x3e3950
releasing non-array memory at 0x3e3980
releasing non-array memory at 0x3e39b0
releasing non-array memory at 0x3e39e0

Anyway, I prefer a design where manually implementing the destructor is not necessary to begin with.

无论如何,我更喜欢一种不需要手动实现析构函数的设计。

#include <array>
#include <memory>

class Foo
{
    std::array<std::shared_ptr<Monster>, 6> monsters;

    Foo()
    {
        for (int i = 0; i < 6; ++i)
        {
            monsters[i].reset(new Monster());
        }
    }

    virtual ~Foo()
    {
        // nothing to do manually
    }
};

回答by Carl Norum

Your second example is correct; you don't need to delete the monstersarray itself, just the individual objects you created.

你的第二个例子是正确的;您不需要删除monsters数组本身,只需删除您创建的单个对象。

回答by Daniel

It would make sens if your code was like this:

如果您的代码是这样的,那将是有道理的:

#include <iostream>

using namespace std;

class Monster
{
public:
        Monster() { cout << "Monster!" << endl; }
        virtual ~Monster() { cout << "Monster Died" << endl; }
};

int main(int argc, const char* argv[])
{
        Monster *mon = new Monster[6];

        delete [] mon;

        return 0;
}

回答by Eric H

You delete each pointer individually, and then you delete the entire array. Make sure you've defined a proper destructor for the classes being stored in the array, otherwise you cannot be sure that the objects are cleaned up properly. Be sure that all your destructors are virtual so that they behave properly when used with inheritance.

您单独删除每个指针,然后删除整个数组。确保为存储在数组中的类定义了适当的析构函数,否则无法确定对象是否被正确清理。确保所有的析构函数都是虚拟的,以便在与继承一起使用时它们的行为正确。