понедельник, 5 марта 2012 г.
Qt и шаблоны
Не пытайтесь создать шаблонный класс, использующий мета-возможности Qt - в текующей реализации (Qt 4.8) ключевое слово template перед заголовком класса и макрос Q_OBJECT в его приватном блоке вещи несовместимые (просто шаблонный наследник QObject имет право на существование, но ведь это уже совсем другая история)
Поведение системы сборки Qt
QГрабля#4
Во многих случаях вам не удастся тривиальным образом скомпилировать код, который определяет класс, использующий расширенные возможности Qt, в том же файле, в котором расположена функция main - этот класс едва ли будет обработан утилитой MOC.
Решение
Всегда определяйте Qt-классы в отдельных заголовочных файлах. Реализация такого класса допустима как in situ, так в *.cpp-файле.
UPD
Также об этой проблеме можно почитать в небольшой ветке форума Qt
Во многих случаях вам не удастся тривиальным образом скомпилировать код, который определяет класс, использующий расширенные возможности Qt, в том же файле, в котором расположена функция main - этот класс едва ли будет обработан утилитой MOC.
Решение
Всегда определяйте Qt-классы в отдельных заголовочных файлах. Реализация такого класса допустима как in situ, так в *.cpp-файле.
UPD
Также об этой проблеме можно почитать в небольшой ветке форума Qt
Управление памятью в Qt
QГрабля#3
Известно, что немалая часть объектов Qt, с которыми приходится иметь дело, в той или иной мере являются контейнерами для других объектов, иногда это непосредственно так (например, для layout'ов), иногда вырождается в повсеместно существующую возможность назначить объекту некоторого родителя. Так или иначе, крайне часто вы передаете в метод (в т. ч. конструктор) объекта указатель на другой объект. Не таким уж странным в таком случае кажется решение создать объект на стеке, а в случае необходимости его куда-то передать просто использовать оператор взятия адреса.
Однако Qt в рамках своей юрисдикции сама управляет памятью - если вы удаляете объект, его деструктор автоматически удаляет всех своих детей и (вероятно) элементы, содержащиеся в нем. Естесственно, ей невозможно знать, был ли создан указатель операцией new, или он указывает на объект, для которого вовсе не освобождалась память в куче - при удалении вашему указателю сделают delete, что выльется в реальной практике в backtrace и memory dump на экран при завершении Qt-шного приложения, если этот указатель увел delete на стек. Однако если вы все объекты будете создавать в куче не заботясь об их удалении, то вы получите утечки памяти. Ясно, что позаботиться обо всех объектах также невозможно разумным образом - в частности, не удалить экземпляр QApplication (QCoreApplication) без странных костылей типа
int returnCode = app->exec();
delete app;
return returnCode;
которых вы никогда не увидите ни в одном руководстве по Qt. Ровно те же проблемы возникнут с объектом главного окна приложения.
Решение.
Все Qt-шные объекты и их наследники создавайте в динамической памяти, следя за тем, что вы или верно поддерживаете естесственную для Qt иерархию объектов (на отношении родитель-потомок), либо разумным образом удаляете их самостоятельно. Все объекты, являющиеся корнями иерархий (не имеющие родителей) создавайте на стеке, обеспечивая их автоматическое удаление. Иначе говоря, остерегайтесь когда-либо применять операцию взятия адреса к Qt-объектам, а в остальном управляйте памятью обычным образом.
UPD
Несомненно более точно и тонко проблему освещает таки документация Qt
Известно, что немалая часть объектов Qt, с которыми приходится иметь дело, в той или иной мере являются контейнерами для других объектов, иногда это непосредственно так (например, для layout'ов), иногда вырождается в повсеместно существующую возможность назначить объекту некоторого родителя. Так или иначе, крайне часто вы передаете в метод (в т. ч. конструктор) объекта указатель на другой объект. Не таким уж странным в таком случае кажется решение создать объект на стеке, а в случае необходимости его куда-то передать просто использовать оператор взятия адреса.
Однако Qt в рамках своей юрисдикции сама управляет памятью - если вы удаляете объект, его деструктор автоматически удаляет всех своих детей и (вероятно) элементы, содержащиеся в нем. Естесственно, ей невозможно знать, был ли создан указатель операцией new, или он указывает на объект, для которого вовсе не освобождалась память в куче - при удалении вашему указателю сделают delete, что выльется в реальной практике в backtrace и memory dump на экран при завершении Qt-шного приложения, если этот указатель увел delete на стек. Однако если вы все объекты будете создавать в куче не заботясь об их удалении, то вы получите утечки памяти. Ясно, что позаботиться обо всех объектах также невозможно разумным образом - в частности, не удалить экземпляр QApplication (QCoreApplication) без странных костылей типа
int returnCode = app->exec();
delete app;
return returnCode;
которых вы никогда не увидите ни в одном руководстве по Qt. Ровно те же проблемы возникнут с объектом главного окна приложения.
Решение.
Все Qt-шные объекты и их наследники создавайте в динамической памяти, следя за тем, что вы или верно поддерживаете естесственную для Qt иерархию объектов (на отношении родитель-потомок), либо разумным образом удаляете их самостоятельно. Все объекты, являющиеся корнями иерархий (не имеющие родителей) создавайте на стеке, обеспечивая их автоматическое удаление. Иначе говоря, остерегайтесь когда-либо применять операцию взятия адреса к Qt-объектам, а в остальном управляйте памятью обычным образом.
UPD
Несомненно более точно и тонко проблему освещает таки документация Qt
QГрабля#2
Если ваш класс использует систему свойств Qt, то вы можете неожиданно получить проблему на стадии компиляции при попытке вызвать setProperty.
( <YourClass or ParentClass>::setProperty("PropertyName", propertyValue); )
Вам сообщат что-то в духе
"no known conversion for argument 2 from <propertyValueType> to ‘const QVariant&"
Проблема связана с тем, что по известным причинам свойства имеют тип QVariant, а в данном блоке кода компилятору просто не известен этот тип.
Решение
Включайте заголовочный файл <QVariant> (QtCore/QVariant> в файлы-определения классов,
использующих свойства Qt. (или даже в main-файл)
Если ваш класс использует систему свойств Qt, то вы можете неожиданно получить проблему на стадии компиляции при попытке вызвать setProperty.
( <YourClass or ParentClass>::setProperty("PropertyName", propertyValue); )
Вам сообщат что-то в духе
"no known conversion for argument 2 from <propertyValueType> to ‘const QVariant&"
Проблема связана с тем, что по известным причинам свойства имеют тип QVariant, а в данном блоке кода компилятору просто не известен этот тип.
Решение
Включайте заголовочный файл <QVariant> (QtCore/QVariant> в файлы-определения классов,
использующих свойства Qt. (или даже в main-файл)
Этим сообщением я начну небольшую серию постов про грабли, с которыми, вероятно, столкнется каждый начинающий пользователь фреймворка Qt. Тривиальных вещей здесь не будет, они прекрасно изложены в первую очередь в документации самого Qt, которая вряд ли имеет равных себе по качеству, охвату и незанудности.
QГрабля#1
Если в приватной секции определения класса, использующего метаобъектную систему Qt, вы забыли указать макрос Q_OBJECT, а затем исправили свою оплошность, то вы вполне можете снова (и снова, и снова...) получить ошибку компиляции со словами в духе "undefined reference" и "vtable of <YourClass>" в строках клиентского кода, использующих в вашем классе дополнительные возможности наследников QObject (сигналы и слоты, свойства, возможности интроспекции).
Подобное может произойти в том случае, если ранее ваш класс, определенный без макроса Q_OBJECT уже успешно компилировался (то есть, дополнительные возможности не использовались) - и в папке сборки уже лежит Makefile, сгенерированный по *.pro-файлу утилитой qmake. Дело в том, что даже после внесенных исправлений, пересборка проекта заключается в вызове make, подхватывающей старый Makefile, который не вызывает MOC для файлов вашего класса (так что даже make clean не поможет).
Решение
Вручную удалите Makefile в директории сборки проекта и пересоберите его.
Так же полезно завести в директории ~/bin файлик с содержимым вроде
QГрабля#1
Если в приватной секции определения класса, использующего метаобъектную систему Qt, вы забыли указать макрос Q_OBJECT, а затем исправили свою оплошность, то вы вполне можете снова (и снова, и снова...) получить ошибку компиляции со словами в духе "undefined reference" и "vtable of <YourClass>" в строках клиентского кода, использующих в вашем классе дополнительные возможности наследников QObject (сигналы и слоты, свойства, возможности интроспекции).
Подобное может произойти в том случае, если ранее ваш класс, определенный без макроса Q_OBJECT уже успешно компилировался (то есть, дополнительные возможности не использовались) - и в папке сборки уже лежит Makefile, сгенерированный по *.pro-файлу утилитой qmake. Дело в том, что даже после внесенных исправлений, пересборка проекта заключается в вызове make, подхватывающей старый Makefile, который не вызывает MOC для файлов вашего класса (так что даже make clean не поможет).
Решение
Вручную удалите Makefile в директории сборки проекта и пересоберите его.
Так же полезно завести в директории ~/bin файлик с содержимым вроде
#!/bin/sh
if [ -e "Makefile" ]
then
make clean
rm Makefile
fi
qmake -project
qmake
make
(не забудьте сделать chmod +x <имя файла> и убедиться в том, что ~/bin есть в переменной окружения PATH (иначе можно ее туда добавить, дописав в ~/.profile строку
PATH="$HOME/bin:$PATH" ))
... и затем собирать проекты вызовом этого скрипта. У меня это выглядит так:
qqmake
среда, 4 января 2012 г.
Подборка литературы
по Embedded Linux. И одна из книг в новом (2010 год) издании - прекрасное практическое руководство.
воскресенье, 1 января 2012 г.
Мучает info?
Когда-нибудь Emacs придется освоить, ну а пока - перенаправляйте:
user@host cwd$ info something | less
user@host cwd$ info something | less
Подписаться на:
Сообщения (Atom)