Когда я использую указатели в Qt?
Я программировал Qt какое-то время, и мне интересно, какая разница между этими двумя случаями:
case1:
Заголовок:
QPushButton * button;
исходный файл:
button = new QPushButton(this);
button->setText("Button");
button->resize(100,100);
и
Случай 2:
Заголовок:
QPushButton button;
Источник:
button.setParent(this);
button.setText("Button");
button.resize(100,100);
Оба создают кнопку, но когда я должен использовать первый и когда последний случай? И в чем разница между ними?
Ответы
Ответ 1
Управление памятью Qt работает с иерархиями объектов, когда родительский объект автоматически удаляет дочерние объекты при уничтожении. Вот почему программы Qt всегда используют указатели в подобных случаях.
Управление памятью с помощью Qt:
Qt поддерживает иерархию объектов. Для виджетов (видимых элементов) эти иерархии представляют собой порядок укладки самих виджетов, а для не-виджетов они просто выражают "собственность" на объекты. Qt удаляет дочерние объекты вместе с их родительским объектом.
Ответ 2
Разница между первым и вторым случаем заключается в том, что при использовании указателей и оператора new
для выделения кнопки память для кнопки выделяется в свободном хранилище (куче). Во втором выражении память выделяется в стеке.
Есть две причины, по которым вы предпочитаете выделять память в свободном хранилище, чем стек.
- Стек имеет ограниченный размер, и если вы убьете бюджет своего стека, ваша программа выйдет из строя с переполнением стека. В свободном хранилище можно выделить гораздо больше памяти, и если сбой памяти не удался, все, что обычно происходит, это то, что генерируется исключение
bad_alloc
.
- Распределение в стеке строго последнее в первом (LIFO), что означает, что ваша кнопка не может существовать дольше, чем блок кода (между
{...}
), который выделяет память. Когда память распределяется в свободном хранилище, вы, как программист, полностью контролируете время, в течение которого память остается в силе (хотя небрежность может вызвать утечку памяти).
В вашем случае, если кнопка просто должна существовать в течение всей функции вызова, вам, вероятно, будет достаточно выделить кнопку в стеке; если кнопка должна быть действительной для гораздо более длительного использования в свободном магазине
Ответ 3
В первом случае вы динамически выделяете кнопку (это означает, что она будет уничтожена при уничтожении родителя). Во втором случае кнопка исчезнет, когда закончится кодовый блок (это означает, что он выходит за рамки).
Используйте первый, когда вы хотите QObject
, на который вы ссылаетесь, чтобы больше, чем просто блок, в котором он был создан.
В контексте класса, к которому вы обращаетесь (при условии, что button
является переменной-членом в обоих случаях), это не имеет большого значения.
Также вы можете использовать указатели при использовании полиморфизма.
Ответ 4
Полезное конкретное использование: при публикации пользовательских событий, содержащих подробные данные, например:
/** support SWI... prolog_edit:edit_source(File) */
struct reqEditSource : public QEvent {
QString file;
QByteArray geometry;
reqEditSource(QString file, QByteArray geometry = QByteArray())
: QEvent(Type(User+1)), file(file), geometry(geometry) {}
};
вы можете "стрелять и забывать" их:
qApp->postEvent(this, new reqEditSource(files[i], p.value(k).toByteArray()));
Событие будет удалено после его доставки.
Ответ 5
Многие функции в Qt, которые принимают объект как аргумент, фактически принимают указатель на объект. Это потому, что передача объекта "по значению" фактически создала бы копию объекта (через конструктор копирования) и передала бы эту копию! Создание новой копии объекта имеет много накладных расходов. В то же время передача объекта "по ссылке", то есть как указатель, будет просто передавать 32-разрядный адрес памяти, что очень облегчает работу.