Можно ли удалить не новый объект? - PullRequest
14 голосов
/ 04 декабря 2010

У меня есть объект с вектором указателей на другие объекты в нем, что-то вроде этого:

class Object {
    ...
    vector<Object*> objlist;
    ...
};

Теперь объекты будут добавлены в список обоими этими способами:

Object obj;
obj.objlist.push_back(new Object);

и

Object name;
Object* anon = &name;
obj.objlist.push_back(anon);

Если создать деструктор просто

~Object {
    for (int i = 0; i < objlist.size(); i++) {
        delete objlist[i];
        objlist[i] = NULL;
    }
}

Будут ли какие-либо неблагоприятные последствия с точки зрения того, когда он пытается удалить объект, который не былсоздан с новым?

Ответы [ 4 ]

34 голосов
/ 04 декабря 2010

Да, будут отрицательные последствия.

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

Помимо двухкратного вызова деструктора, вы также попытаетесь освободить блок памяти, который был никогда не выделен. Оператор new предположительно помещает объекты в кучу; delete ожидает найти объект в той же области, которую оператор new размещает. Тем не менее, ваш объект, который не был выделен с new, живет в стеке. Скорее всего, это приведет к сбою вашей программы (если она не сработала после повторного вызова деструктора).

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

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

5 голосов
/ 04 декабря 2010

Нет, вы можете только delete что вы new ed

Object* anon = &name;

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

1 голос
/ 04 декабря 2010

На самом деле вы спрашиваете, безопасно ли удалять объект, не выделенный с помощью new через оператор delete, и если да, то почему?

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

См. ответ zneak , почему ваш первоначальный вопрос не 't приводит к безопасной работе, и почему область действия для name действительно имеет значение.

1 голос
/ 04 декабря 2010

Это не будет работать - если вы delete объект, который не был выделен new, вы нарушили правила или оператор delete.

Если вам нужно, чтобы объекты вашего векторного хранилища могли или не могли бы быть удалены, вам нужно как-то отслеживать это. Одним из вариантов является использование интеллектуального указателя, который отслеживает, является ли указанный объект динамическим или нет. Например, shared_ptr<> позволяет вам указать объект deallocator при создании shard_ptr<> и, как указано в документации:

Например, освобождающий блокировщик «no-op» полезен при возврате shared_ptr статически распределенному объекту

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

...