Russian Qt Forum
Ноябрь 26, 2024, 06:50 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: 1 ... 3 4 [5] 6 7 ... 10   Вниз
  Печать  
Автор Тема: Основы удаления объектов  (Прочитано 86001 раз)
kibsoft
Хакер
*****
Offline Offline

Сообщений: 625


Просмотр профиля WWW
« Ответ #60 : Январь 08, 2010, 23:00 »

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

Цитировать
потому что мой возраст, ну ни как не назовешь детством

niXman, из вас прям-таки прет тематика Qt..
Записан

http://kibsoft.ru - Download the Qt Media Encoding Library here

The apps that were written using QtMEL:
http://srecorder.com - Screen recording software
niXman
Гость
« Ответ #61 : Январь 09, 2010, 00:10 »

kibsoft, а вы в Qt видите только гуй?  Шокированный
ну...учитесь батенька Подмигивающий
Записан
kibsoft
Хакер
*****
Offline Offline

Сообщений: 625


Просмотр профиля WWW
« Ответ #62 : Январь 09, 2010, 00:43 »

Причем тут GUI..Вы мне говорите что я тут не по теме пишу на форуме, а я вам доказываю, что вы тоже не туда клоните..
Записан

http://kibsoft.ru - Download the Qt Media Encoding Library here

The apps that were written using QtMEL:
http://srecorder.com - Screen recording software
Dendy
Гость
« Ответ #63 : Январь 09, 2010, 02:28 »

А не вызываются слоты потому, что слоты находятся в удаляемом виджете, поэтому еще до разрушения детей все сигналы с ним разрываются (disconnect).

Бзззз! Ответ неверен.

kibsoft, внимание, отвечает Александр Друзь.

1. На вопрос удаляются ли дочерние виджеты, ответ - да, удаляются.
2. На вопрос почему не вызывается слот crash(), ответ - не потому что соединение было разорвано.
3. На вопрос "а почему тогда?" ответ кроется в недрах C++.

Qt использует виртуальные методы для вызова методов по имени (сигналов и слотов). А как мы знаем из теории - виртуальные методы в деструкторах не работают, поскольку отнаследованный обьект (ваш Widget) был разрушен до базового (QObject). Именно в деструкторе QObject удаляюся дочерние обьекты, сигналы destroyed() от которых уже не могут вызвать виртуальный метод в Widget.
Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« Ответ #64 : Январь 09, 2010, 02:36 »

интриги, скандалы, расследования...
Записан
Dendy
Гость
« Ответ #65 : Январь 09, 2010, 02:41 »

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

Вы меня запутали. В этой фразе вы сами себе противоречите. С одной стороны вы говорите, что знаете зачем нужны виртуальные деструкторы, и тут же утверждаете, что к автоматическому удалению они отношения не имеют. И что в приведённом мной тривиальном примере виртуальные деструкторы якобы не играют никакой роли. Вы уж определитесь, знаете ли вы таки зачем нужны виртуальные деструкторы. Как тогда QObject автоматически удаляет своё дочернее дерево обьектов, которым он установлен как parent?

Может вы всё ещё думаете, что под автоматическим удалением подразумевается выход из области видимости? Ну так мы же не о терминах спорим. Вопрос изначально стоял по другому: "Как виртуальные деструкторы помогают избежать явного вызова delete в коде."
Записан
Dendy
Гость
« Ответ #66 : Январь 09, 2010, 02:56 »

Ну и, строки вида
Код
C++ (Qt)
new QLabel( &widget ); // here
, конечно, вполне корректны с точки зрения Qt, но с точки зрения С++ нехорошо смотрятся Улыбающийся Я бы всё-таки написал
Код
C++ (Qt)
QLabel lbl = new QLabel( &widget ); // here
, ведь мы, всё же, используем С++, и, думаю, лучше всегда пользоваться его соглашениями при оформлении кода.

Qt - и есть C++, всё что корректно с точки зрения Qt - корректно и с точки зрения C++. А приведённый пример, как написали бы вы, именно что некорректен что точки зрения C++, поскольку lbl больше нигде не используется в коде, о чём компилятор выдаст предупреждение. Если вы подразумевали под lbl некий экземпляр шаблона (неясно, ибо у вас ошибка в коде, пропущен знак указателя) - то логически он там быть не может, поскольку время жизни lbl не ограничено областью видимости.
Записан
ilot
Гость
« Ответ #67 : Январь 09, 2010, 07:24 »

С одной стороны вы говорите, что знаете зачем нужны виртуальные деструкторы, и тут же утверждаете, что к автоматическому удалению они отношения не имеют. И что в приведённом мной тривиальном примере виртуальные деструкторы якобы не играют никакой роли. Вы уж определитесь, знаете ли вы таки зачем нужны виртуальные деструкторы. Как тогда QObject автоматически удаляет своё дочернее дерево обьектов, которым он установлен как parent?
Код из QObject, который отвечает за удаление потомков:
Код:
QObject::~QObject()
{
    .....
    if (!d->children.isEmpty())
        d->deleteChildren();

    qt_removeObject(this);
    .....
}

void QObjectPrivate::deleteChildren()
{
    const bool reallyWasDeleted = wasDeleted;
    wasDeleted = true;
    // delete children objects
    // don't use qDeleteAll as the destructor of the child might
    // delete siblings
    for (int i = 0; i < children.count(); ++i) {
        currentChildBeingDeleted = children.at(i);
        children[i] = 0;
        delete currentChildBeingDeleted;
    }
    children.clear();
    currentChildBeingDeleted = 0;
    wasDeleted = reallyWasDeleted;
}
Каждый наследник QObject хранит список указателей на собственных потомков. Деструкторы производных классов завершают свою работу вызовом деструктора базового класса. Так, проходя всю цепочку наследования, в конечном итоге вызывается деструктор ~QObject(). В деструкторе ~OObject() проверяется наличие потомков, и если они есть, то выполняется их удаление (метод deleteChildren()). Как видно из исходника объект прекрасно знает о своих потомках и в ходе своего разрушения явно вызывает деструктор для каждого из них.
Итак, а где же виртуальный деструктор?? Конечно, вот же он:
Код:
virtual ~QObject();
Деструктор ~QObject() объявлен виртуальным! А зачем? Пример:
Код:
class Foo: public QObject{
enum{size = 100};
int* m_data;
public:
Foo(QObject* pobj = 0):QObject(pobj){
m_data = new int[size];
}
~Foo(){
delete []m_data;
std::cout << "Foo destructor" << std::endl;
}
};
int main(int argc, char *argv[])
{
QObject* pobj = new Foo;
//do something...
delete pobj;//вызывается деструктор Foo
}
Если бы деструктор ~QObject не был виртуальным, то для указателя pobj был бы вызван деструктор ~QObject, а не ~Foo. Виртуальность позволила выполнить полиморфных вызов нужного деструктора, и, как следствие, выполнить правильную зачистку и избежать утечки памяти. Это и есть назначение виртуальных деструкторов - выполнение корректной зачистки при работе с объектом не напрямую, а через его интерфейс. Как можно видеть, в примере количество new и delete совпадают. Точно так же оно совпадает во внутренней реализации Qt. Сами по себе виртуальные деструкторы никак не помогают избежать явного вызова delete в коде.

Приведенный вами пример, в котором delete для соответствующего new отсутствует, демонстрирует особенность фреймворка. По этому поводу я уже отвечал, что согласен с тем, что учитывать особенности библиотеки нужно обязательно (http://www.prog.org.ru/index.php?topic=11963.msg75112#msg75112).

Dendy, я ответил на ваш вопрос?
Записан
ilot
Гость
« Ответ #68 : Январь 09, 2010, 07:32 »

детский сад, честное слово...

ilot, именно вам я давал ссылки по теме. повторю:
1. http://ru.wikipedia.org/wiki/Абстрактная_фабрика_(шаблон_проектирования)
2. http://ru.wikipedia.org/wiki/Строитель_(шаблон_проектирования)
3. http://ru.wikipedia.org/wiki/Одиночка_(шаблон_проектирования)
эти три паттерна, плюс принцип RAII(http://ru.wikipedia.org/wiki/RAII), избавляют программиста от головной боли и утечек памяти.
niXman, я смотрел эти ссылки и даже ответил (http://www.prog.org.ru/index.php?topic=11965.msg75056#msg75056).
В той же Абстрактной фабрике выполняется явное удаление экземпляров. Посмотрите пример для нее - увидите, что она никак не избавляет программиста от утечек памяти, если он забудет в нужном месте delete вызвать. Более того, в том же примере допущена ошибка, способная в перспективе привести к весьма трудноуловимой утечке памяти.
« Последнее редактирование: Январь 09, 2010, 07:34 от ilot » Записан
Dendy
Гость
« Ответ #69 : Январь 09, 2010, 07:45 »

Спасибо за развёрнутое обьяснение что такое виртуальные деструкторы, может кому и пригодится.

Dendy, я ответил на ваш вопрос?

Судя по тому, что продолжаете себе противоречить - нет. И обратите внимание - я не предлагал мне разжёвывать зачем нужны виртуальные деструкторы. Всё что я хотел - чтобы вы обьяснили это себе, можно даже дома перед зеркалом. И да, ваш пример несостоятелен, вы пытаетесь в нём обьяснить зачем нужны виртуальные деструкторы, в то время как пример демонстрирует ровно наоборот.

Ответьте на вопрос: зачем обьявлен:
Код:
QObject* pobj = new Foo;
вместо:
Код:
Foo* pobj = new Foo;
?
Записан
Dendy
Гость
« Ответ #70 : Январь 09, 2010, 07:53 »

Забыл процитировать этот момент.

Приведенный вами пример, в котором delete для соответствующего new отсутствует, демонстрирует особенность фреймворка.

Приведённый мною пример ни разу не демонстирирует особенность фреймфорка. Он демонстрирует исключительно возможности C++. Все без исключения классы с виртуальным деструктором предназначены для того, чтобы убрать явный delete из клиентского кода.
Записан
ilot
Гость
« Ответ #71 : Январь 09, 2010, 08:20 »

Судя по тому, что продолжаете себе противоречить - нет.
уму непостижимо где вы видете противоречие ...
И да, ваш пример несостоятелен, вы пытаетесь в нём обьяснить зачем нужны виртуальные деструкторы, в то время как пример демонстрирует ровно наоборот.
именно, пытаюсь объяснить зачем они есть и как используются. А попутно показываю, что сами по себе они не помогают сократить количество записей (как вам угодно) delete коде.
Ответьте на вопрос: зачем обьявлен:
Код:
QObject* pobj = new Foo;
вместо:
Код:
Foo* pobj = new Foo;
?
А зачем вообще нужен полиморфизм? И как он работает? Деструкторы, как обычные функции, могут быть виртуальными, и механизм их вызова точно такой же.
Каждый класс, наследованный от QObject, хранит список указателей на своих потомков:
Код:
typedef QList<QObject*> QObjectList;
Как вы можете видеть указатели имеют тип QObject, и чтобы при удалении потомков корректно вызывались именно их деструкторы (а не деструктор ~QObject()), необходимо реализовать полиморфный вызов. Все, другого назначения у виртуального деструктора нет. Как он помогает сократить количество записей delete в коде знаете, наверное, только вы.
Записан
Dendy
Гость
« Ответ #72 : Январь 09, 2010, 08:39 »

Так в вашем примере и нет никакого полиформизма. А вы пытаетесь показать, что он есть и этим оправдать delete pobj. Попытайтесь всё таки обьяснить, зачем в примере экзмепляр обьекта обьявляется в указателе QObject*, а не Foo*.
Записан
ilot
Гость
« Ответ #73 : Январь 09, 2010, 09:00 »

Так в вашем примере и нет никакого полиформизма. А вы пытаетесь показать, что он есть и этим оправдать delete pobj.
Неправда ваша. Я же показал, что деструктор ~QObject() - виртуальный. Это значит, что QObject - Foo образуют полиморфную иерархию. Этот и только этот факт дает нам право удалять объект типа Foo через указатель на QObject. Выше я так и написал
Цитировать
Виртуальность позволила выполнить полиморфный вызов нужного деструктора
Если бы здесь не было полиморфизма (как вы утверждаете), то при выполнении delete pobj вызывался бы деструктор QObject. Не верите мне, можете запустить приведенный пример, и убедиться, что в консоль выводится "Foo destructor".
Попытайтесь всё таки обьяснить, зачем в примере экзмепляр обьекта обьявляется в указателе QObject*, а не Foo*.
Я провожу аналогию с хранением в QObject указателей на свои потомки. Потомками могут быть любые объекты, тип которых наследован от QObject. Хранятся эти указатели в следующем виде:
Каждый класс, наследованный от QObject, хранит список указателей на своих потомков:
Код:
typedef QList<QObject*> QObjectList;
И полиморфизм здесь задействуется для того, чтобы вызывать нужные деструкторы, а не ~QObject() для каждого потомка. В своем предыдущем посте http://www.prog.org.ru/index.php?topic=11963.msg75199#msg75199 я даже специально подчеркнул ключевую фразу.
« Последнее редактирование: Январь 09, 2010, 09:35 от ilot » Записан
Dendy
Гость
« Ответ #74 : Январь 09, 2010, 09:42 »

Я же показал, что деструктор ~QObject() - виртуальный.

Так в том то и вопрос - зачем он в вашем примере виртуальный? Что это даёт в вашем примере? Почему деструктор QObject не обычный в вашем примере?

Виртуальность позволила выполнить полиморфный вызов нужного деструктора

Зачем, если в вашем случае указатель на Foo живёт в одной области видимости с его конструктором? Ваш пример наглядно демонстрирует бесполезность какого-либо полиморфизма. И как следствие выводы о необходимости явного delete pobj ложны.

Я провожу аналогию с хранением в QObject указателей на свои потомки.

Примеры не демонстрируют аналогии, а показывают вариант развития событий. Ваш пример не показывает необходимость полиморфизма. Потрудитесь написать пример, в котором полиморфизм таки будет продемонстрирован. Вот тогда и посчитаем количество new/delete в коде.
« Последнее редактирование: Январь 09, 2010, 09:46 от Dendy » Записан
Страниц: 1 ... 3 4 [5] 6 7 ... 10   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.098 секунд. Запросов: 23.