Когда я использую указатели в 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-разрядный адрес памяти, что очень облегчает работу.