Удалить оператор и массивы? - PullRequest
6 голосов
/ 06 января 2010

У меня есть abstract Base класс и Derived класс.

int main ()
{
  Base *arrayPtr[3];

  for (int i = 0; i < 3; i++)
  {
    arrayPtr[i] = new Derived();
  }

  //some functions here

  delete[] arrayPtr;

  return 0;
}

Я не уверен, как использовать оператор удаления. Если я удалю массив указателей базового класса, как показано выше, вызовет ли этот вызов деструкторы объектов производного класса и очистит ли память?

Ответы [ 11 ]

10 голосов
/ 06 января 2010

Вы должны перебрать элементы вашего массива, delete каждый из них. Затем вызовите delete [] для массива, если он был выделен динамически с использованием new[].

В вашем примере кода массив расположен в стеке, поэтому вы не должны вызывать delete [] для него.

Также убедитесь, что в вашем классе Base есть деструктор virtual.

Ссылка: Когда мой деструктор должен быть virtual.

10 голосов
/ 06 января 2010

Нет, вы должны явно удалить каждый элемент в массиве:

for (int i = 0; i < 3; ++i)
{
    delete arrayPtr[i];
}
2 голосов
/ 06 января 2010

Вы должны вместо этого сделать:

 for ( int = i; i < 3; i++ )
 {
    delete arrayPtr[i];
 }

И вам не следует делать delete[] arrayPtr;, поскольку вы пытаетесь освободить / удалить стек, выделенный arrayPtr.

Еще одна вещь, которую следует учитывать, - это использование std::vector указателей вместо массива. И если вы используете компилятор, который реализует TR1, вы также можете использовать std::vector из std::tr1::shared_ptr вместо необработанных указателей, и тогда вам не придется беспокоиться об удалении этих объектов самостоятельно.

Пример:

{
    std::vector< std::tr1::shared_ptr<Base> > objects;
    for (int i=0; i < 3; ++i)
    {
        objects.push_back(std::tr1::shared_ptr<Base>(new Derived()));
    }
}  // here, once "objects" exit scope, all of your Derived objects are nicely deleted
1 голос
/ 06 января 2010

То, что у вас там, - неопределенное поведение - ошибка. Каждый вызов new должен соответствовать delete; каждый вызов new[] должен соответствовать delete[]. Эти два отдельных и не могут быть смешаны.

В опубликованном вами коде у вас есть массив указателей на Base, размещенных в стеке. Затем вы вызываете delete[] для массива, выделенного в стеке - вы не можете этого сделать. Вы можете только delete[] массив, выделенный в куче с new[].

Вам нужен вызов delete для каждого элемента, выделенного с помощью new - или, желательно, использовать класс контейнера, например std::vector, вместо использования массива.

1 голос
/ 06 января 2010

Оператор удаления должен совпадать с оператором new для этого указателя, если он был выделен с помощью new[], необходимо вызвать delete[] и наоборот;

int* pInt = new int;
delete pInt; OK
delete [] pInt; WRONG

int[] pIntArr = new int[3];
delete [] pIntArr; OK
delete pIntArr; WRONG

В вашем случае есть что-то еще не так - вы пытаетесь delete, что было выделено в стеке. Это не сработает.

В данном конкретном случае вы должны удалить каждый указатель отдельно.

1 голос
/ 06 января 2010

Обратите внимание, что отсутствует:

int main() {
  boost::ptr_vector<Base> v;
  for (int i = 0; i < 3; i++) v.push_back(new Derived());
  // some functions here, using v[0] through v[2]
}

Проверьте Контейнеры указателя Boost out.

1 голос
/ 06 января 2010

Нет, вы не можете этого сделать. Как предложили другие, вы должны пройти через каждый элемент и удалить его. Это очень простое правило для запоминания. Если вы использовали new, используйте delete, а если new[], то delete[]

1 голос
/ 06 января 2010

Вы должны удалить элементы массива по отдельности. Вы также должны убедиться, что в вашем базовом классе есть виртуальный деструктор. Вы также можете рассмотреть возможность сделать его массивом (или, что еще лучше, std :: vector) интеллектуальных указателей, таких как boost :: shared_ptr.

0 голосов
/ 06 января 2010

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

Чтобы использовать оператор new массива, вы должны объявить так:

Base *array;
array = new Base[3];
/* do stuff */
delete[] array;

Это выделяет непрерывную область памяти для трех объектов - обратите внимание, что у вас есть массив базовых объектов, а не массив указателей на базовые объекты.

0 голосов
/ 06 января 2010

Нет, это не совсем то, что вы хотите.

Здесь следует обратить внимание на два момента:

  1. Синтаксис delete[] arrayPtr используется, если вы динамически выделяете массив, например:

    arrayPtr = new (Base *)[mylength];
    

    В вашем случае, однако, у вас есть статически распределенный массив, поэтому нет необходимости его удалять. Однако вам необходимо удалить отдельные элементы в массиве:

    for ( int = i; i < 3; i++ )
         delete arrayPtr[i];
    
  2. Второй момент, о котором вам нужно позаботиться, - сделать деструктором класса Base виртуальным:

    class Base
    {
        virtual ~Base();
        /* ... */
    };
    

    Это гарантирует, что когда вы вызываете delete для Base *, который фактически указывает на Derived, вызывается деструктор Derived, а не просто деструктор Base.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...