Russian Qt Forum

Qt => Общие вопросы => Тема начата: serg_hd от Май 26, 2011, 20:42



Название: QScopedPointer forward declaration
Отправлено: serg_hd от Май 26, 2011, 20:42
Такой код:

myclass.h:
Код
C++ (Qt)
#ifndef MYCLASS_H
#define MYCLASS_H
 
#include <QScopedPointer>
 
class MyClass2;
 
class MyClass
{
public:
 MyClass();
 ~MyClass();
 QScopedPointer<MyClass2> _ptr;
 
};
 
#endif // MYCLASS_H
 

myclass.cpp:
Код
C++ (Qt)
#include "myclass.h"
#include "myclass2.h"
 
MyClass::MyClass()
{
this->_ptr.reset(new MyClass2);
}
 
MyClass::~MyClass() { }
 

myclass2.h:
Код
C++ (Qt)
#ifndef MYCLASS2_H
#define MYCLASS2_H
 
#include "myclass.h"
 
class MyClass2
{
public:
 MyClass2() { };
 ~MyClass2() { };
};
 
#endif // MYCLASS2_H
 

main.cpp:
Код
C++ (Qt)
#include "myclass.h"
 
int main(int argc, char *argv[])
{
MyClass obj;
}
 

Вопрос в том, зачем для MyClass'а, в котором мембером является QScopedPointer, при операции forward declaration необходимо обязательно объявлять деструктор, может кто-то выяснил это? Без деструктора бооольшой ерор. Думал может по умолчанию деструктор идёт как virtual (в доке по QScopedPointer такой какбэ запрещается), но если с ним, то всё ок. Не люблю такой подход - объявлять их пустыми, класс MyClass ведь никем не наследуется чтоб объявлять и виртуалить энтот деструктор...


Название: Re: QScopedPointer forward declaration
Отправлено: asvil от Май 26, 2011, 20:57
А еще для определения функции, которая будет выполняться параллельно функции main необходимо писать целый класс. Наверно просто смиритесь.


Название: Re: QScopedPointer forward declaration
Отправлено: Akon от Май 26, 2011, 22:28
Потому что в этом случае тип для скопед-поинтера (MyClass2) будет полностью определенным (в деструкторе скопед-поинтера находится что-то типа checked_delete).

Просто подумай, как компилятор будет генерировать код и какая информация будет доступна в точках генерации деструкторов.


Название: Re: QScopedPointer forward declaration
Отправлено: zenden от Май 26, 2011, 22:32
Пусть лучше требует деструктор, чем ведёт себя как std::auto_ptr на некоторых компиляторах, который в таких случаях память освобождает, но деструктор не вызывает.


Название: Re: QScopedPointer forward declaration
Отправлено: serg_hd от Май 26, 2011, 22:36
Пусть лучше требует деструктор, чем ведёт себя как std::auto_ptr на некоторых компиляторах, который в таких случаях память освобождает, но деструктор не вызывает.
жестоко)


Название: Re: QScopedPointer forward declaration
Отправлено: serg_hd от Май 26, 2011, 22:47
Потому что в этом случае тип для скопед-поинтера (MyClass2) будет полностью определенным (в деструкторе скопед-поинтера находится что-то типа checked_delete).

Просто подумай, как компилятор будет генерировать код и какая информация будет доступна в точках генерации деструкторов.

Код структуры, которая чистит объект qscopedpointer'a:
Код
C++ (Qt)
template <typename T>
struct QScopedPointerDeleter
{
   static inline void cleanup(T *pointer)
   {
       // Enforce a complete type.
       // If you get a compile error here, read the secion on forward declared
       // classes in the QScopedPointer documentation.
       typedef char IsIncompleteType[ sizeof(T) ? 1 : -1 ];
       (void) sizeof(IsIncompleteType);
 
       delete pointer;
   }
};
 

Требует завершённый тип, даже в доку посылает, с этим понятно.
Но причём тут описание пустого деструктора парента-то? Чем конкретно это помогает? Интересен сам подход.
Получается, что если описано тело пустого деструктора класса, мембером которого является qscopedpointer, который, в свою очередь завязан с объектом при forward declaration, то этот qscopedpointer начинает понимать тип объекта, на который ссылается, как завершённый. Мистика.


Название: Re: QScopedPointer forward declaration
Отправлено: Igors от Май 27, 2011, 00:42
Но причём тут описание пустого деструктора парента-то? Чем конкретно это помогает? Интересен сам подход.
Получается, что если описано тело пустого деструктора класса, мембером которого является qscopedpointer, который, в свою очередь завязан с объектом при forward declaration, то этот qscopedpointer начинает понимать тип объекта, на который ссылается, как завершённый. Мистика.
Если деструктор MyClass объявлен, то удаление "инстанциируется" в этом деструкторе - а там MyClass2 уже известен. А если нет, то код деструктора по умолчанию должен быть создан в main - но здесь не получается т.к. scoped не знает тип удаления.

Вообще расходы на изучение таких мелких классов часто превышают их usability :) Еще один момент - затрудняется отладка - пока до тела доберешься...


Название: Re: QScopedPointer forward declaration
Отправлено: serg_hd от Май 27, 2011, 01:03
Если деструктор MyClass объявлен, то удаление "инстанциируется" в этом деструкторе - а там MyClass2 уже известен.
Что значит "инстанциируется" в деструкторе, т.е. в чём разница, деструктор по умолчанию это или объявленный мной? В обоих же случаях будет вызван деструктор QScopedPointer'а... Получается, что если деструктор по умолчанию, то тип, используемый в QScopedPointer'е - неизвестен (интересно почему).

Вообще расходы на изучение таких мелких классов часто превышают их usability :) Еще один момент - затрудняется отладка - пока до тела доберешься...
так ведь дело не в изучении классов, а в понимании данного подхода.


Название: Re: QScopedPointer forward declaration
Отправлено: Igors от Май 27, 2011, 02:12
Что значит "инстанциируется" в деструкторе, т.е. в чём разница, деструктор по умолчанию это или объявленный мной? В обоих же случаях будет вызван деструктор QScopedPointer'а... Получается, что если деструктор по умолчанию, то тип, используемый в QScopedPointer'е - неизвестен (интересно почему).
Компилятор создает код когда увидит что темплейт используется (т.е. заряжено конкретным типом). Это происходит в конкретной единице трансляции (cpp файле) и к этому моменту все подробности должны быть компилятору известны. Вы объявили деструктор MyClass, значит что в main он вызовется - а что он там дальше будет делать - за это ответит код созданный в том cpp где деструктор. Напр. просто перенесите тело ~MyClass::MyClass() в main.cpp - и компилятор опять не пропустит.

так ведь дело не в изучении классов, а в понимании данного подхода.
Да нет там никакого особого/великого подхода  :) Просто необходимость удаляться при выходе их ф-ции/контекста возникает часто - вот и придумали утилитарный класс. Им можно пользоваться или нет - варианты примерно равноценны.