Добавление указателей к QList

Мне нужно вставить указатели классов (унаследованных от QObject) в QList. Я знаю, что можно использовать следующий синтаксис:

.h

QList<MyObject*> list;

.cpp

list.append(new MyObject("first", 1));
list.append(new MyObject("second", 2));
...

а затем освободить память:

if(!list.isEmpty())
{
    qDeleteAll(list);
    list.clear();
}

Это должно быть действительным и не вызывает утечек памяти (насколько мне известно). Однако мне нужно инициализировать объекты, прежде чем добавлять их в коллекцию. Может ли следующий фрагмент кода вызвать некоторые ошибки, такие как утечка памяти или висячие указатели (я буду использовать тот же способ удаления указателей, что и выше)?

MyObject *obj;

for(i = 0; i < 5; i++)
{   
    obj = new MyObject();
    if(!obj.Init(i, map.values(i)))
    {
        // handle error
    }
    else
    {
        list.append(obj);
    }
}

Спасибо.


person Routa    schedule 15.07.2010    source источник
comment
просто примечание: if (list.isEmpty ()) при использовании qDeleteAll () является избыточным, я бы просто пропустил его.   -  person Frank Osterfeld    schedule 15.07.2010


Ответы (4)


если вы позаботитесь о «obj» (выделенном, но не инициализированном экземпляре) в случае «// обработать ошибку», ваш код в порядке.

person akira    schedule 15.07.2010

Вместо этого используйте QSharedPointer.

QList<QSharedPointer<MyObject> > list;

Чтобы освободить память, вам нужно только сделать

if(!list.isEmpty())
{
    list.clear();
}

Добавить в список

list.append(QSharedPointer<MyObject>(new MyObject("first", 1)));
list.append(QSharedPointer<MyObject>(new MyObject("second", 2)));
person PBareil    schedule 17.05.2017

Используйте RAII (выделение ресурсов - инициализация). Инициализируйте объект напрямую в конструкторе.

Тогда код будет выглядеть так:

for(i = 0; i < 5; i++)
{   
    list.append( new MyObject( i, map.values(i)));
    // In case of initialization failure, throw exception from the constructor
}
person Cătălin Pitiș    schedule 15.07.2010
comment
что, если в его среде не разрешены исключения? - person akira; 15.07.2010
comment
... тогда необходимо найти другой механизм для сообщения об ошибках. Это может быть что-то вроде функции getLastError (возможно, потокобезопасной). Но почему недопустимые исключения? В вопросе ничего не упоминается, поэтому я оставил его простым. - person Cătălin Pitiș; 15.07.2010
comment
На самом деле я рассматривал создание исключения. В случае сбоя инициализации я хочу получить сообщение об ошибке от объекта для отладки (в настоящее время используется общедоступный метод obj.getError ()). Я знаю, что можно сообщать об ошибках с исключениями (например, бросая строку), но в настоящее время я играю с возвращаемыми значениями и сообщениями об ошибках (например, с библиотеками Qt), и я хотел бы остаться на этом пути. Это основная причина, по которой я спросил, подходит ли последний код. - person Routa; 15.07.2010
comment
И я хотел бы добавить, что в некоторых ситуациях мне нужны аналогичные функции при гораздо более сложных инициализациях, и поэтому размещение всего в конструкторе кажется не очень разумным. - person Routa; 15.07.2010
comment
другой механизм ... да, именно поэтому я поднял этот вопрос. так как мы не знаем мотивацию показанного кода, я не буду вводить какие-либо другие концепции и просто отвечу на вопрос. есть 1000 способов инициализации объекта и 1000 причин, почему выбрать один из 1000 :) - person akira; 15.07.2010

Вы можете использовать QScopedPointer ..

Из документации Qt 4.6,

Класс QScopedPointer хранит указатель на динамически выделяемый объект и удаляет его при уничтожении. Управление объектами, размещенными в куче, вручную сложно и подвержено ошибкам, обычно в результате утечки памяти в коде и его трудно поддерживать. QScopedPointer - это небольшой служебный класс, который сильно упрощает это, назначая владение памятью на основе стека для распределения кучи, более широко называемое получение ресурсов - инициализация (RAII).

Надеюсь, это поможет..

Редактировать:

Например,

Вы будете использовать,

QScopedPointer<QWidget> p(new QWidget());

вместо того

QWidget *p = new QWidget();

и добавьте QScopedPointer в свой QList, не беспокоясь об утечке памяти и висячих указателях.

person liaK    schedule 15.07.2010
comment
поэтому внутренний цикл выглядит так: QScopedPointer ‹MyObject› obj (new MyObject ()); if (obj- ›Init (map.values ​​(i)) {list.append (obj.take ());} ... добавьте это в ответ, чтобы увидеть преимущество. - person akira; 15.07.2010
comment
извините, я не могу понять ваш пример. Но просто добавил базовый пример из документации, чтобы прояснить ситуацию ... Я не добавляю это раньше в надежде, что люди все равно найдут его в документации .. :) - person liaK; 15.07.2010
comment
какая часть моего трехстрочного примера непонятна? кстати, ваш пример приведет к segfault, потому что ptr с областью видимости все еще ВЛАДЕЕТ экземпляром, поэтому я использовал .take (). - person akira; 15.07.2010
comment
QScopedPointer не подлежит копированию и поэтому не может быть добавлен в QList. - person jturcotte; 11.09.2013