Массив C++ указателей: удалить или удалить []?

Cosider следующий код:

class Foo
{
    Monster* monsters[6];

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

    virtual ~Foo();
}

Каков корректный деструктор?

это:

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

или это:

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

У меня в настоящее время есть высший конструктор, и все работает okey, но конечно я не вижу, протекает ли это, оказывается...

Лично, я думаю, что вторая версия является намного более логическим рассмотрением, что я делаю. Так или иначе, что "надлежащий" путь состоит в том, чтобы сделать это?

40
задан Brian Tompsett - 汤莱恩 6 July 2015 в 19:31
поделиться

7 ответов

удалить[] монстров;

Неверно, потому что monsters не является указателем на динамически выделяемый массив, он является массивом указателей. Как член класса он будет уничтожен автоматически при уничтожении экземпляра класса.

Другая реализация является правильной, так как указатели в массиве указывают на динамически выделяемые объекты Monster.

Обратите внимание, что при текущей стратегии выделения памяти вы, вероятно, захотите объявить свой собственный конструктор копирования и оператор назначения копирования, чтобы непреднамеренное копирование не вызывало двойного удаления. (Если вы хотите предотвратить копирование, вы можете объявить их частными и фактически не реализовывать их.)

45
ответ дан 27 November 2019 в 01:10
поделиться

Ваш второй пример верен; вам не нужно удалять сам массив monsters, только отдельные объекты, которые вы создали.

3
ответ дан 27 November 2019 в 01:10
поделиться

Было бы понятно, если бы ваш код был таким:

#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;
}
1
ответ дан 27 November 2019 в 01:10
поделиться

Вы удаляете каждый указатель по отдельности, а затем удаляете весь массив. Убедитесь, что вы определили правильный деструктор для классов, хранящихся в массиве, иначе вы не сможете быть уверены, что объекты будут очищены должным образом. Убедитесь, что все ваши деструкторы являются виртуальными, чтобы они вели себя правильно при использовании наследования.

0
ответ дан 27 November 2019 в 01:10
поделиться

Для new вы должны использовать delete . Для new [] используйте delete [] . Ваш второй вариант правильный.

39
ответ дан 27 November 2019 в 01:10
поделиться

Второй вариант верен в данных обстоятельствах (ну, в любом случае, наименее ошибочный).

Правка: «минимум ошибок», поскольку в исходном коде нет веских причин для использования new или delete в первую очередь, поэтому вам, вероятно, следует просто использовать:

std::vector<Monster> monsters;

В результате будет более простой код и более четкое разделение обязанностей.

11
ответ дан 27 November 2019 в 01:10
поделиться

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

Как видите, вы пытаетесь освободить с неправильной формой удаления (не массив или массив), и указатель 0x22ff38 никогда не возвращался вызовом new. Вторая версия показывает правильный результат:

[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

В любом случае, я предпочитаю дизайн, в котором ручная реализация деструктора для начала не обязательна.

#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
    }
};
6
ответ дан 27 November 2019 в 01:10
поделиться
Другие вопросы по тегам:

Похожие вопросы: