Удаление соответствующего элемента, на который указывает каждый элемент массива указателей в c ++ - PullRequest
1 голос
/ 26 сентября 2019

Учтите, что у меня есть массив указателей, объявленных как:

MyObject** myArr = new MyObject*[someSize] ;

И затем я назначаю некоторые объекты с помощью

myArr[i] = myObjectInstance

Теперь я хочу удалить каждый элемент, на который указываеткаждый указатель этого массива.Так каков правильный способ сделать это?Я не думаю, что delete[] myArr работает.

Ответы [ 5 ]

2 голосов
/ 26 сентября 2019

Вы можете использовать стандартный алгоритм std::for_each и объект функции std::default_delete.

Вот демонстрационная программа

#include <iostream>
#include <memory>
#include <algorithm>

struct A
{
    static size_t i;
    A() { i++; }
    ~A() { std::cout << --i << ": ~A()\n"; }
};

size_t A::i = 0;

int main() 
{
    const size_t N = 10;

    A **p = new A *[N];

    for ( size_t i = 0; i < N; i++ )
    {
        p[i] = new A();
    }

    std::for_each( p, p + N, std::default_delete<A>() );

    delete []p;

    return 0;
}

Ее вывод

9: ~A()
8: ~A()
7: ~A()
6: ~A()
5: ~A()
4: ~A()
3: ~A()
2: ~A()
1: ~A()
0: ~A()

Если вы хотите удалить элементы массива в обратном порядке относительно порядка их создания, вы можете написать

std::for_each( std::reverse_iterator<A **>( p + N ), 
               std::reverse_iterator<A **>( p ), std::default_delete<A>() );
2 голосов
/ 26 сентября 2019
for (int i = 0; i < someSize; ++i)
    delete myArr[i];

Это могло бы помочь.Как бы вы ни поступали, вам придется посещать каждый элемент и удалять его по отдельности, а затем удалять массив с помощью delete [] myArr;.

. Но динамическое размещение массивов может быть грязным делом.В соответствии с традициями SO, я рекомендую std::vector (или любой другой контейнер STL, который имеет смысл), если вы можете его использовать.Вам все равно придется по отдельности удалять все элементы, но теперь вам не нужно беспокоиться о самом массиве.

Как упоминалось в комментариях к вашему вопросу, если вы используете умные указатели на каждый элемент, то выне нужно ничего удалять вручную.

2 голосов
/ 26 сентября 2019

Сначала удалите каждый объект, затем весь массив:

for(int i = 0; i < someSize; i++)
{
    delete myArr[i];
}
delete[] myArr;
1 голос
/ 26 сентября 2019

Предположим, что все myObjectInstance являются указателями на кучу выделенных объектов (если не так, см. Ответ @ JoãoPaulo), и никакие пользовательские new или delete не задействованы.

for (size_t idx = 0; idx < someSize; ++idx)
    delete myArr[idx];
delete[] myArr;

Какая потенциальная ловушка?

Ну, их много.Что если инициализируются только некоторые элементы массива?Другой будет в неопределенном состоянии, и удаление их приводит к неопределенному поведению.

Кроме того, что, если несколько элементов массива указывают на один и тот же объект?Затем вы пытаетесь удалить объект несколько раз.Это также приводит к неопределенному поведению.

Это не значит, что вы не можете использовать этот наивный метод, оно просто напоминает вам некоторые предварительные условия:

  1. Убедитесь, что каждый элемент массиваинициализируется либо «указателем на некоторый выделенный объект кучи», либо nullptr (удаление nullptr безопасно).
  2. Убедитесь, что вы не удаляете объект дважды.
1 голос
/ 26 сентября 2019

Acctualy, delete[] myArr правильно, потому что myArr является динамически размещаемым объектом.

Возможно, вам придется освободить некоторое количество myArr[i] раньше, если вы сделаете любое myArr[i] = myObjectInstance, где myObjectInstance динамически размещаетсяНапример:

myArr[i] = new MyObject;

delete myArr[i]; будет аварийно завершить работу, если:

MyObject m;
myArr[i] = &m;

В случае динамического распределения всех позиций вы можете использовать for для освобождения памяти:

for (int i = 0; i < someSize; ++i)
    delete myArr[i];
...