Глава 14. Создание элементов графического интерфейса
не реагирует на нажатие мышкой. Совершенствование этого примера, а также
дальнейшее изучение свойств объектов и виджетов мы продолжим в следующих
параграфах, посвящённых обработке событий.
14.2
Управление памятью. Иерархии объектов
Как мы уже знаем, каждый объект может иметь «родительские» и «дочер-
ние» объекты. Таким образом объекты организуют в иерархические структуры
напоминающие дерево. Каждый из объектов может содержать дочерние объек-
ты, а также иметь родительский объект. Отношение между объектами можно
задать либо воспользовавшись параметром конструктора (при создании), или
же с помощью метода QObject::setParent(). Обычно пользуются первым спо-
собом, то есть задают родительский объект при конструировании.
//Задаём родительский виджет с помощью конструктора
QLabel ∗ l L a b e l = new QLabel ( lSomeWidget ) ;
//Задаём родительский виджет с помощью метода QObject : : s e t P a r e n t ( )
QPushButton ∗ lPushButton = new QPushButton ;
lPushButton−>s e t P a r e n t ( lSomeWidget ) ;
Если виджет содержит компоновщики, то и компоновщики и все размещён-
ные в нём виджеты автоматически получат «родителя» (ведь каждый визуаль-
ный элемент наследует от QWidget, а тот в свою очередь наследует от QObject).
Объекты также могут менять «родителя», для этого достаточно вызвать метод
QObject::setParent (QObject *)
с указателем на другой родительский объ-
ект. Объектную иерархию можно увидеть наглядно, воспользовавшись мето-
дом dumpObjectTree() класса QObject. Он выводит в стандартный поток вы-
вода тип и имя всех дочерних объектов. Зададим имена для объектов lLabel и
lPushButton
:
l L a b e l −>setObjectName ( " C h i l d L a b e l " ) ;
lPushButton−>setObjectName ( " C h i l d P u s h B u t t o n " ) ;
Если теперь вызвать метод dumpObjectTree() для объекта lSomeWidget, то
получим вывод:
SomeWidget : :
QLabel : : C h i l d L a b e l
QPushButton : : ChildPushButton
Когда родительский объект удаляют, дочерние объекты тоже будут удалены
из памяти перед удалением родительского. То же самое происходит и при удале-
нии виджетов — все дочерние виджеты в визуальной иерархии тоже удаляются.
Это позволяет управлять высвобождением памяти в программе.
Управление памятью важно, поскольку неуправляемое выделение памяти
приводит к утечке памяти в программе — ситуации, когда программа не осво-
бождает память. Если такое неуправляемое выделение памяти повторяется пе-
риодически, а сама программа выполняется относительно долго, то со временем
программа будет занимать всё больше места в оперативной памяти. Наконец,
таким образом можно исчерпать всю доступную память, что приведёт к аварий-
ному завершению программы и исчерпанию ресурсов операционной системы.
Программирование на языке С++ в среде Qt Creator
14.2. Управление памятью. Иерархии объектов
381
Например, при использовании ключевого слова new память выделяется в ди-
намически распределяемой памяти (так называемой «куче» — heap). Динами-
ческая память должна быть освобождена от созданных объектов с помощью
ключевого слова delete для того, чтобы избежать утечки памяти (memory leak).
Объекты, созданные в динамически распределяемой памяти могут существовать
столько, сколько необходимо. Динамическая память не будет освобождена авто-
матически, поэтому программист должен самостоятельно следить за высвобож-
дением выделенной памяти. Рассмотрим следующий пример:
#include
#include
#include
#include
i n t main ( i n t argc , char ∗ a r g v [ ] )
{
Q A p p l i c a t i o n l A p p l i c a t i o n ( a r g c , a r g v ) ;
//(1) Память в динамически-распределяемой памяти (heap)
QWidget ∗ lSomeWidget = new QWidget ( 0 ) ; //Окно
//Задаём родительский виджет с помощью конструктора
QLabel ∗ l L a b e l = new QLabel ( lSomeWidget ) ;
//Задаём родительский виджет с помощью метода QObject : : s e t P a r e n t ( )
QPushButton ∗ lPushButton = new QPushButton ;
lPushButton−>s e t P a r e n t ( lSomeWidget ) ;
l L a b e l −>s e t T e x t ( " L a b e l " ) ;
l L a b e l −>move ( 1 0 , 1 0 ) ;
lPushButton−>s e t T e x t ( " B u t t o n " ) ;
lPushButton−>move ( 5 0 , 1 0 ) ;
//(1) Память в динамически-распределяемой памяти (heap)
lSomeWidget−>r e s i z e ( 1 5 0 , 5 0 ) ;
lSomeWidget−>show ( ) ;
return l A p p l i c a t i o n . e x e c ( ) ;
}
Хотя с первого взгляда программа может показаться корректной (она компи-
лируется и выполняется), в ней есть ошибка, связанная с некорректным управле-
нием памятью. Для того, чтобы проанализировать использование памяти в про-
грамме, воспользуемся программой Valgrind. Это свободно-распространяемая
программа для Linux с открытым кодом. Среда Qt Creator поддерживает ра-
боту с этой программой для анализа использования памяти и оптимизации про-
грамм на Qt.
Перейдите в режим анализа Analyse (Анализ) воспользовавшись кнопкой на
панели переключения режимов работы слева или воспользуйтесь комбинацией
клавиш Ctrl+6. Снизу под окном редактирования появится дополнительная па-
нель. В выпадающем списке выберите Valgrind Memory Analyzer (Анализатор
памяти Valgrind) и запустите процесс анализа (нажмите на кнопку с пиктограм-
мой треугольника на панели или выберите в главном меню Analyze->Valgrind
Memory Analyzer
(Анализ->Анализатор памяти Valgrind). Начнётся анализ ра-
боты программы и программа запустится. Затем закройте окно программы. По-
сле завершения работы на панели появится сообщение об утечке памяти (см.
рис. 14.1).
Сообщение указывает на строку:
QWidget ∗ lSomeWidget = new QWidget ( 0 ) ; //Окно
© 2015 Алексеев Е. Р., Злобин Г. Г., Костюк Д. А., Чеснокова О. В., Чмыхало А. С.
382
Do'stlaringiz bilan baham: |