Какова динамика оператора C ++ delete? - PullRequest
4 голосов
/ 24 ноября 2010

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

Я знаю, что delete освобождает память.Что мне интересно, так это то, как он обрабатывает более сложные случаи?

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

class MyClass
{
public:
    MyClass();
    ~MyClass()
    {
        delete [] intArray;
    }
    //public members here
private:
    int* intArray;
};

Предполагая, что класс как-то выделяет памятьдля intArray, а затем отпустите его в деструкторе. Что если я использовал класс следующим образом: MyClass* myClass = new MyClass(); и выпустил его позже с delete myclass;

Как delete обрабатывает освобождение всехобъем памяти?Деструктор класса вызывается первым, чтобы освободить всю память, выделенную классом (то есть int* intArray), а затем освободить память, выделенную для хранения класса?

Что если бы у меня был такой класс:

class MyClass
{
public:
    MyClass();
    ~MyClass()
    {
        delete anotherMyClass;
    }
    //public members here
private:
    MyClass* anotherMyClass;
};

Если предположить, что anotherMyClass не выделен конструктору, который очень быстро израсходует память, что если бы была цепочка MyClasses, связанных друг с другом, как связанный список?Будет ли оператор удаления в деструкторе работать в этом случае?Будет ли каждый anotherMyClass рекурсивно освобождаться при вызове деструктора?

Существуют ли какие-то странные уловки или предостережения с известными вам операторами new и delete?

Ответы [ 2 ]

10 голосов
/ 24 ноября 2010

Учитывая указатель (p) на динамически размещенный объект, delete делает две вещи:

  1. Вызывает деструктор динамически размещаемого объекта. Обратите внимание, что когда ~MyClass() завершается, вызывается деструктор для любых переменных-членов типа класса.
  2. Освобождает память, занятую динамически распределяемым объектом.

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

Если вам нужно освободить память, указанную intArray, вам нужно delete в деструкторе MyClass.

Однако почти во всем коде C ++ вам не нужно об этом беспокоиться. Вы должны использовать умные указатели, такие как shared_ptr, unique_ptr, auto_ptr и scoped_ptr для автоматического управления динамически размещаемыми объектами. Ручное управление ресурсами в лучшем случае затруднено, и его следует избегать везде, где это возможно.

Это часть более широкой идиомы «Управление ресурсами, ограниченным областью действия» (SBRM, также называемый «Получение ресурсов - инициализация» или RAII). Это, безусловно, самый важный шаблон проектирования, который нужно понимать и использовать везде в коде C ++.

Если в вашем классе вы объявили это вместо:

boost::scoped_ptr<int> intArray;

затем, когда объект scoped_ptr<int> будет уничтожен, он освободит указатель, который он содержит. Тогда вам не нужно выполнять какую-либо работу, чтобы уничтожить объект вручную.

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


Во втором примере приведен связанный список, который выглядит следующим образом:

x -> y -> z -> 0

у вас будет порядок операций, который выглядит следующим образом:

delete x;
  x.~MyClass();
    delete y;
      y.~MyClass();
        delete z;
          z.~MyClass();
            delete 0;
          [free memory occupied by z]
      [free memory occupied by y]
  [free memory occupied by x]

Объекты в связанном списке будут уничтожены в обратном порядке.

1 голос
/ 24 ноября 2010
delete intArray;

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

delete[] intArray;

Да, я знаю, delete intArray может появится прекрасно работать на определенных системах с определенными версиями компилятора при определенных параметрах компилятора - или это может быть не так.Это неопределенное поведение для вас.

Кроме того, вы должны следовать правилу трех .Определение собственного деструктора, но использование неявно определенного конструктора копирования и оператора назначения копирования - это путь к катастрофе.

...