Russian Qt Forum

Qt => Общие вопросы => Тема начата: Orfus от Сентябрь 30, 2011, 14:33



Название: ->deleteLater()
Отправлено: Orfus от Сентябрь 30, 2011, 14:33
Доброго времени суток. Объясните пожалуйста, что происходит при таком раскладе.
Код
C++ (Qt)
QObject *obj = new QObject(this);
obj->deleteLater();
obj=new QObject(this);

Какой объект будет удалён? Тот, что был создан в первой строке или третей? И будет ли вообще удалён?  ???
Этот вопрос терзает меня уже не первый день.


Название: Re: ->deleteLater()
Отправлено: Пантер от Сентябрь 30, 2011, 14:36
Первый, конечно. Не путай объект и указатель на объект.


Название: Re: ->deleteLater()
Отправлено: Alex Custov от Сентябрь 30, 2011, 14:37
obj - это не объект, а всего лишь указатель на него. Поэтому указанный код будет работать нормально, удалится первый объект.


Название: Re: ->deleteLater()
Отправлено: Igors от Сентябрь 30, 2011, 14:47
Первый, но конструкция потенциально опасна - неизвестно когда дело дойдет до удаления и будет ли этот момент подходящим


Название: Re: ->deleteLater()
Отправлено: Orfus от Сентябрь 30, 2011, 14:57
Премного благодарен за ответы.

Первый, но конструкция потенциально опасна - неизвестно когда дело дойдет до удаления и будет ли этот момент подходящим
Насчёт этого волнений нет ;)


Название: Re: ->deleteLater()
Отправлено: ieroglif от Сентябрь 30, 2011, 16:07
Первый, но конструкция потенциально опасна - неизвестно когда дело дойдет до удаления и будет ли этот момент подходящим

Код
C++ (Qt)
QObject *obj = new QObject(this);
Объявили переменную под названием obj, размером с "указатель", типа "указатель на QObject". в памяти выделилось место.
В эту память (переменную) положили адрес нового созданного объекта типа QObject.
Код
C++ (Qt)
obj->deleteLater();
объекту, который располагается по адресу, записанному в переменной obj, дали команду "самоудались при первом возможно случае"
Код
C++ (Qt)
obj=new QObject(this);
в переменную obj записали новый адрес - это новый объект типа QObject

итого: в чём эта конструкци потенциально опасна?


Название: Re: ->deleteLater()
Отправлено: asvil от Сентябрь 30, 2011, 16:44
Код:
неизвестно когда дело дойдет до удаления и будет ли этот момент подходящим
Хотя жаба и прочие обладатели gc не беспокоятся по этому поводу.

P.S. ах да это же сиплюплюс


Название: Re: ->deleteLater()
Отправлено: Igors от Сентябрь 30, 2011, 19:00
Насчёт этого волнений нет ;)
Лучше чтобы они были :)  Добавим всего одну строчку

Код
C++ (Qt)
QObject *obj = new QObject(this);
obj->deleteLater();
delete obj;        // новая строка
obj=new QObject(this);
И становится совсем непросто ответить "а как же это будет(?) работать"  :)


Название: Re: ->deleteLater()
Отправлено: Авварон от Сентябрь 30, 2011, 19:04
будет


Название: Re: ->deleteLater()
Отправлено: Orfus от Сентябрь 30, 2011, 19:14
Лучше чтобы они были :)  Добавим всего одну строчку

Код
C++ (Qt)
QObject *obj = new QObject(this);
obj->deleteLater();
delete obj;        // новая строка
obj=new QObject(this);
И становится совсем непросто ответить "а как же это будет(?) работать"  :)

При таком раскладе сдаётся мне произойдёт чего нибудь не то при попытке обратится к объекту который насильно удалён был.


Название: Re: ->deleteLater()
Отправлено: Igors от Сентябрь 30, 2011, 21:02
При таком раскладе сдаётся мне произойдёт чего нибудь не то при попытке обратится к объекту который насильно удалён был.
Так что, написал delete - уже насильник? :) Работать будет т.к. деструктор вычистит из EventLoop все  события посланные удаляемому. Все implicit действия чем-то похожи и первое впечатление почти всегда "ой как здорово! (элегантно, изящно и.т.п.)". Потом правда выясняется что это не совсем так.


Название: Re: ->deleteLater()
Отправлено: Yuriy от Сентябрь 30, 2011, 23:57
Предлагаю использовать valgrind.

Я даже и не подозревал, какие утечки памяти вытворял такими deleteLater или WA::DeleteOnClose и т.д., в общем на мой взгляд верном коде. В своих двух проектах сотворил 1000 исправлений за два дня.

Утечки могут быть не только при использовании оператора типа Delete. Утечек хватает при некорректном использовании Qt-шных виджетов.

Я и представить не  мог, что к примеру злосчастный QRubberBand может наковырять 10Мб утечек памяти, при этом с виду код абсолютно стандартный. Про QSQlite вообще отдельная тема, до поиска утечек даже не подозревал, что у меня такие руки кривые, хотя многие классы использую в стандартном порядке, как Assistent порекомендовал


Название: Re: ->deleteLater()
Отправлено: asvil от Сентябрь 30, 2011, 23:59
звучит несколько маркетологовски, если несложно, покажите diff


Название: Re: ->deleteLater()
Отправлено: Yuriy от Октябрь 01, 2011, 00:26
Да нет никакого маркетинга, слава богу.
Есть такая фича, когда запускаешь проект из под valgrind, то он начинает валить memory leak'и и прочие вещи в окно Результат выполнения в QtCreator.
И когда он насчитывает их более 1000, то просто перестает об этом писать, мол иди правь свой проект !
Я думаю что такая участь может постигнуть любого, не я один такой  ;D


Название: Re: ->deleteLater()
Отправлено: andrew.k от Октябрь 01, 2011, 01:32
При таком раскладе сдаётся мне произойдёт чего нибудь не то при попытке обратится к объекту который насильно удалён был.
Так что, написал delete - уже насильник? :) Работать будет т.к. деструктор вычистит из EventLoop все  события посланные удаляемому. Все implicit действия чем-то похожи и первое впечатление почти всегда "ой как здорово! (элегантно, изящно и.т.п.)". Потом правда выясняется что это не совсем так.
Что-то я сильно сомневаюсь, что это будет работать.

"Deleting a QObject while pending events are waiting to be delivered can cause a crash."
deleteLater посылает объекту событие:
QEvent::DeferredDelete   52   The object will be deleted after it has cleaned up.
Я уверен что будет коре.


Название: Re: ->deleteLater()
Отправлено: Igors от Октябрь 01, 2011, 10:25
"Deleting a QObject while pending events are waiting to be delivered can cause a crash."
Я так понимаю что здесь речь идет о том что нельзя удалять объект если в EventLoop другой нитки есть для него события

Я уверен что будет коре.
"Прошу исполнить"  :)

Связавшись с deleteLater все время придется думать типа "а что будет в той или иной ситуации?". А для начала мы вообще расписались что это будет работать только в событийной (event-driven) схеме. Потребуется консольная/сетевая версия - и как выцарапывать то deleteLater неясно, а в чужом коде - вообще завал. Впрочем это стандартная проблема любого "deferred delete" и Qt не хуже остальных.

Наверное лучше не спешить лезть головой в петлю, и без крайней необходимости штучки типа deleteLater не использовать


Название: Re: ->deleteLater()
Отправлено: Авварон от Октябрь 01, 2011, 12:03
Наверное лучше не спешить лезть головой в петлю, и без крайней необходимости штучки типа deleteLater не использовать
не согласен


Название: Re: ->deleteLater()
Отправлено: ieroglif от Октябрь 01, 2011, 13:18
простите, конечно, но пока ещё сомневаюсь.
до сих пор не сталкивался с проблемами на deleteLater().
Код
C++ (Qt)
QObject *obj = new QObject(this);
obj->deleteLater();
delete obj;        // новая строка
obj=new QObject(this);
это бессмысленно.
предложи реальный пример, а не абстрактно выдуманный, да который к тому же явно никогда в практике нормального (т.е. думающего над тем что пишется) программиста не встречающегося..


Название: Re: ->deleteLater()
Отправлено: andrew.k от Октябрь 01, 2011, 13:21
а что будет если сделать так?
Код
C++ (Qt)
QObject *obj =new QObject();
delete obj;
delete obj;
 
Вот то же самое будет и в том примере.
Как евентлуп получив сообщение, что нужно удалить объект узнает, что он уже был удален?

А нитки там не при чем. Просто при обработке событий может потребоваться обращение к самому объекту, который уже удален.
Просто без множества потоков такую ситуацию надо умудриться получить)


Название: Re: ->deleteLater()
Отправлено: Igors от Октябрь 01, 2011, 15:23
а что будет если сделать так?
Код
C++ (Qt)
QObject *obj =new QObject();
delete obj;
delete obj;
 
Вот то же самое будет и в том примере.
Проверим
Код
C++ (Qt)
#include <QtGui>
 
struct MyObj : public QObject {
virtual ~MyObj( void )
{
qDebug() << "destroy";
}
};
 
int main(int argc, char **argv)
{
QApplication app(argc, argv);
MyObj * obj = new MyObj();
obj->deleteLater();
delete obj;
 
app.exec();
 
return 0;
}
 
У меня "destroy" печатается один раз.

Как евентлуп получив сообщение, что нужно удалить объект узнает, что он уже был удален?
Он его просто не получит т.к. деструктор вызовет removePostedEvents (см. исходники)

это бессмысленно.
Просто первые 2 строчки в одном куске кода. 2 последние в другом - и как минимум непросто отследить порядок вызовов
Код
C++ (Qt)
QObject *obj = new QObject(this);
obj->deleteLater();
...
 
Код
C++ (Qt)
delete obj;
obj=new QObject(this);
...
 


Название: Re: ->deleteLater()
Отправлено: Igors от Октябрь 01, 2011, 15:27
не согласен
Ну это Ваше право :) Годика 2 назад я ухватил прекрасный заказ - 80% у меня уже было сделано. Вот только UI там было на wxWidgets. Пришлось подучиться портированию и всему такому


Название: Re: ->deleteLater()
Отправлено: Авварон от Октябрь 01, 2011, 15:47
не согласен
Ну это Ваше право :) Годика 2 назад я ухватил прекрасный заказ - 80% у меня уже было сделано. Вот только UI там было на wxWidgets. Пришлось подучиться портированию и всему такому
К чему этот оффтоп?
А насчет делета - попробуйте удалить sender() в обработке QAbstractItemView::doubleClicked(QModelIndex) делетом.


Название: Re: ->deleteLater()
Отправлено: andrew.k от Октябрь 01, 2011, 16:39
ну значит разработчики предусмотрели защиту от дурака. славно.
но это не значит, что так нужно делать.


Название: Re: ->deleteLater()
Отправлено: Alex Custov от Октябрь 01, 2011, 18:25
Проверим
Код
C++ (Qt)
#include <QtGui>
 
struct MyObj : public QObject {
virtual ~MyObj( void )
{
qDebug() << "destroy";
}
};
 
int main(int argc, char **argv)
{
QApplication app(argc, argv);
MyObj * obj = new MyObj();
obj->deleteLater();
delete obj;
 
app.exec();
 
return 0;
}
 
У меня "destroy" печатается один раз.

А ты хотел чтобы два раза? :) Двойное удаление приводит к битью памяти, которое потом вылезти может где угодно.


Название: Re: ->deleteLater()
Отправлено: Igors от Октябрь 01, 2011, 19:05
Двойное удаление приводит к битью памяти, которое потом вылезти может где угодно.
Та неужели? :) Никогда не слыхал, наверное сильно память бьют (асе электроны разбегаются)