Мой любимый проект пришел к тому, что я должен начать отслеживать время жизни указателя, и я пытаюсь разработать для него какую-то систему. К сожалению, популярный совет использовать умные указатели повсеместно не применим, так как сам Qt API использует голые указатели в каждом случае. Итак, что я придумал, это:
За все, что принадлежит Qt,
QPointer
что делает isNull()
проверьте перед преобразованием в голое.Для всего, что принадлежит мне, используйте умные указатели, как рекомендовано. Я собираюсь пойти с std::
версии здесь.
Дело, которое меня беспокоит. Для объектов, которые переключают владение (например, виджеты добавляются / удаляются из макета)
delete
их вручную, когда это необходимо.Предложения, комментарии, советы? Я сам не очень люблю эту схему.
Во-первых, держите вещи по значению там, где можете. Просмотр каждого использования 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
был сторонним дескриптором объекта C API, который не мог отслеживать время существования объекта данных.
Если право собственности на объект распределяется между потоками, то использование std::shared_ptr
важно: destroyed()
Сигнал можно использовать только в пределах одного потока. К тому времени, когда вы получите информацию об удалении объекта в другом потоке, уже слишком поздно: объект уже уничтожен.
В-третьих, когда вы возвращаете экземпляры динамически создаваемых объектов из фабричных методов, вы должны возвращать их по голому указателю: ясно, что фабрика создает объект для управления кем-то другим. Если вам нужна безопасность исключений, вы можете вернуть std::unique_ptr
вместо.
Для начала, в Риме будь римским.
QT был разработан в самом начале 90-х, и это был большой успех одновременно.
к сожалению, с течением времени QT на самом деле не внедрила новые функции, поэтому сам API имеет очень старый стиль C ++ (и можно ли сказать, стиль Java?)
вы не можете заставить QT внезапно стать C ++ 14, потому что это не так. используйте соглашения популярных QT, когда дело доходит до QT. используйте необработанный указатель, если это было целью разработки платформы. используйте типы значений, когда вы не можете.
Но я не думаю, что вы заставляете QT работать так много с C ++ 14. придерживайтесь идиом QT, как они даны платформой.