Прежде всего, держите вещи по достоинству, где сможете. Просмотрите каждое использование new
, make_unique
и make_shared
с подозрением - вы должны оправдать создание каждого динамического объекта. Если подпоследовательность имеет такое же время жизни, что и родительское, то удерживание по значению не требует больших усилий. Например:
class MyWidget : public QWidget {
Q_OBJECT
QGridLayout m_topLayout{this};
QLabel m_sign{"Hello World"};
public:
MyWidget(QWidget * parent = nullptr) : QWidget{parent} {
m_topLayout.addWidget(&m_sign, 0, 0);
}
};
Вы проезжаете указатели вокруг, но владение объектами ясно, и смена владельца не изменилась. Просто потому, что у QObject
есть родительский элемент, это не означает, что родитель «владеет» им. Если ребенок разрушен до родителя, право собственности прекращается. Используя семантику C++, а именно четко определенный порядок построения и уничтожения членов, вы имеете полный контроль над дочерними жизнями, а родитель QObject
не вмешивается.
Если у вас есть недвижные объекты, у которых есть один владелец, используйте std::unique_ptr
и переместите его.Это способ динамически создать QObject
вокруг вашего собственного кода. Вы можете удалить их из указателя в том месте, где вы делаете свое владение, управляемым родителем QObject
, если таковое имеется.
Если у вас есть объекты с общим достоянием, где их жизнь должна заканчиваться как можно скорее (в случае прекращения действия приложения или уничтожения какого-либо долгоживущего объекта), используйте std::shared_ptr
. Убедитесь, что указатель выделяет пользователей. Например:
class MyData : public QAbstractItemModel { /* ... */ };
class UserWindow : public QWidget {
Q_OBJECT
std::shared_ptr<MyData> m_data; // guaranteed to outlive the view
QTreeView m_view;
public:
void setData(std::shared_ptr<MyData> && data) {
m_data = std::move(data);
m_view.setModel(m_data.data());
}
};
Этот пример, возможно, надуманным, так как в Qt большинство пользователей объектов смотреть destroyed()
сигнал объекта и реагировать на уничтожение объектов. Но это имеет смысл, если, например, m_view
был сторонним дескриптором API C API, который не мог отслеживать время жизни объекта данных.
Если владение объектом является общим для потоков, то использование std::shared_ptr
имеет важное значение: сигнал destroyed()
доступен только для одного потока. Когда вы узнаете об удалении объекта в другом потоке, уже слишком поздно: объект уже уничтожен.
В-третьих, когда вы возвращаете экземпляры динамически создаваемых объектов из заводских методов, вы должны вернуть их открытым голосом: ясно, что фабрика создает объект для управления кем-то другим. Если вам нужна безопасность исключений, вы можете вернуть std::unique_ptr
.
просто используйте умные указатели 'std ::', в чем проблема с ними? небольшое обслуживание? он будет окупиться .. –
@Abhinav Gauniyal Какой из 'std ::' умных указателей вы бы предложили для случая, когда я 1) создал виджет, 2) передал его в макет, и он станет принадлежащим Qt, 3) * возможно * удалить его из макета позже в зависимости от действий пользователя? Удаление чего-то принадлежащего Qt является сбоем. – sigil
«Удаление чего-то принадлежащего Qt - это сбой». Ну нет. В общем, нет. Предположим, у вас есть виджет, который является дочерним элементом другого виджета: вы можете удалить этого ребенка напрямую, даже если он «принадлежит Qt» (через родительский виджет). Поэтому я хотел бы получить больше разъяснений о том, что вас беспокоит, и как именно вы не можете найти решение для этого. – peppe