Когда использовать «удалить»? - PullRequest
5 голосов
/ 27 марта 2012

Я хочу сохранить 10 Obj объект в objList, но я не знаю, когда целесообразно использовать delete в этом случае.Если я использую delete Obj; в строке, где я отмечаю код ниже, будет ли Obj сохраняться в objList?

struct Obj {
    int u;
    int v;
};

vector<Obj> objList;

int main() {
    for(int i = 0; i < 10; i++) {
        Obj *obj = new Obj();
        obj->u = i;
        obj->v = i + 1;
        objList.push_back(*obj);
        // Should i use "delete Obj;" here? 
    }
}

Ответы [ 5 ]

9 голосов
/ 27 марта 2012

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

objList.push_back(*Obj);

Шаг за шагом эта строка выполняет следующие действия:

  1. Обращение к указателю на базовую память кучиObj занимает (возвращает объект Obj)
  2. Вызов конструктора копирования для создания временной копии
  3. Сохранение временной копии в коллекции

Вы не делаетенеобходимо создать этот исходный объект Obj в куче, выделенный локальный стек будет достаточен, как указал @Luchian Grigore.

Obj obj;
objList.push_back(obj);

Вам не нужно вызывать delete для копии в коллекции, коллекции STLбудет обрабатывать эту память сама при удалении элемента, но вам все равно потребуется удалить исходный объект, выделенный в куче.

Было бы лучше, если бы вы сохранили ваши объекты с помощью std::shared_ptr.Этот способ удаления будет вызван, когда будут удалены все ссылки на объект.

std::vector< std::shared_ptr< Obj > > vec;
vec.push_back( std::make_shared( new Obj() ) );
9 голосов
/ 27 марта 2012

Да, вам следует.

Для каждой new в вашей программе должно быть соответствующее delete.

Но вашей программе не нужнодинамическое распределение:

Obj obj;
obj.u = i;
obj.v = i + 1;
objList.push_back(obj);

Кроме того, ваш синтаксис был неправильным - objList.push_back(*Obj); // should be *obj, not *Obj

3 голосов
/ 27 марта 2012

Подумайте о том, что происходит:

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

КСТАТИ:

  • вы можете даже повторно использовать экземпляр объекта, создать и освободить его вне цикла
  • нет необходимости размещать экземпляр Obj в куче

Obj x; х.у = я; x.v = i + 1; objList.push_back (х);

также будет делать

Вам следует прочитать несколько статей о интеллектуальных указателях и контейнерах интеллектуальных указателей. Например. boost :: scoped_ptr, boost :: shared_ptr, std :: auto_ptr. Используя эти парадигмы, обычно нет необходимости вызывать delete самостоятельно.

2 голосов
/ 27 марта 2012

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

vector<Obj *>objList;

Почему? Потому что если это вектор Obj, то вещи, которые вы храните, на самом деле являются копиями значения Obj созданных вами указателей. Элементы objList и созданные вами указатели obj полностью разделены и не связаны! Поэтому, когда вы,

delete obj

Вещи в objList абсолютно полностью никак не затронуты .
Более того, vector<Obj> (без звездочки), сохраняет свой элемент как Obj, и они находятся в стеке , они исчезнут, когда ваша программа выйдет из области видимости!

1 голос
/ 27 марта 2012

Ну, простое правило состоит в том, что каждая переменная, построенная с помощью new, должна быть очищена на delete.

Однако, в зависимости от вашей цели, вам, возможно, не нужно писать delete самостоятельно.

Дома, изучая мрачные детали управления памятью, вы, вероятно, напишите столько же delete, сколько и new.

Профессионалы, однако никогда не используйте delete в аппликативномкод (*).delete - это кодовый запах.Это самый короткий способ утечки памяти при наличии исключений.Профессионалы используют RAII для безопасной работы с исключениями, а именно: умные указатели / умные контейнеры.

(*) в отличие от библиотечного кода, то есть кто-то написал этот shared_ptr класс однажды.

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