|
|||||||
В чем основные отличия умных указателей QPointer, QScopedPointer, QSharedPointer
Время создания: 01.11.2024 14:38
Текстовые метки: qt, c++, си++, умный, указатель, QPointer, QScopedPointer, QSharedPointer
Раздел: Компьютер - Программирование - Язык C++ (Си++) - Библиотека Qt - Принципы написания кода
Запись: xintrea/mytetra_syncro/master/base/1730461115jqk4959m4c/text.html на raw.github.com
|
|||||||
|
|||||||
Умные указатели QPointer, QScopedPointer, QSharedPointer имеют различные тонкости в своей работе. Что бы не забыть в чем они состоят, здесь записываются основные моменты. Указатель QPointer Данный указатель способен указывать и работать только с объектом QObject или с наследниками данного класса. Когда происходит выход этого указателя из области видимости, объект QObject, на который указывает данный указатель, не уничтожается. По сути, основным свойством, которое используется в указателе QPointer является то, что он способен автоматически выставить свое значение в nullptr в тот момент, когда объект QObject, на который он указывает, был удален. Пример использования: // Создание объекта и инициализация указателя QPointer QPointer<ExampleClass> pointer = new ExampleClass(); // Инициализация дополнительного обычного C++ указателя // Метод QPointer data() возвращает обычный C++ указатель ExampleClass *rawPointer = pointer.data(); ... // Удаление объекта, вариант 1 delete pointer.data(); // После удаления объекта, переменная pointer будет равна nullptr // По сути, это произошло удаление объекта через сырой указатель ... // Удаление объекта, вариант 2, чтобы показать что удалять объект можно // через любой указатель, и QPinter узнает об удалении объекта delete rawPointer; // После удаления объекта, переменная pointer будет равна nullptr // Это произойдет потому, что QObject через метаобъектную систему // оповестит указатели QPointer что он был удален. И поэтому // даже при удалении через дополнительный "сырой" указатель, // указатель QPointer узнает что объект был удален и выставит // свое значение в nullptr QPointer полезен, когда нужно временно отслеживать объект, переданный в функцию или присвоенный в классе, но нет необходимости напрямую управлять его удалением. Например, если указатель сохраняется только для выполнения операций и может исчезнуть в любое время, QPointer предотвращает доступ к невалидным объектам. По сути, применять его следует когда объект создается и удаляется где-то ещё, а программист только хочет иметь безопасный указатель на него в другом месте. Это позволяет избежать ситуации, когда удаление объекта в одной части программы вызывает неопределённое поведение в другой части. QPointer<Worker> worker = new Worker(); ... // Где-то происходит удаление delete worker; // Удаляем объект ... if (worker) { worker->doWork(); } else { qDebug() << "Объект больше не существует!"; } Под словом "безопасный" подразумевается только то, что QPointer-указатель на объект всегда станет равным nullptr каким бы способом этот объект не уничтожался (напрямую, через дополнительный указатель, при удалении массива указателей, куда он был положен и т.д.). Саму проверку на существование (на равенство nullptr) никто не отменял! Нельзя просто так взять и вызвать метод у удаленного объекта, ибо будет сегфолт. И еще одно важное свойство QPointer: когда объект, на который указывает QPointer, удаляется, Qt автоматически удаляет все соединения с его сигналами/слотами. Это, как минимум, предотвращает отправку сигналов на несуществующий объект. Указатель QScopedPointer Указатель QScopedPointer, так же как и QPointer, не поддерживает совместное владение объектом. Указатель QScopedPointer способен указывать не только на QObject, но и на любой другой тип. Основное предназначение QScopedPointer состоит в том, что он удаляет объект, на который он ссылается, при выходе из текущего скоупа (другими словами - из области видимости). Это делает его полезным для использования с временными объектами или локальными данными, которые нужно освободить автоматически. Скоуп - это тот текущий блок кода, который ограничен фигурными скобками. Как уже было сказано, QScopedPointer не не поддерживает совместное владение объектом, а значит не позволяет копировать себя. Он обеспечивает строгую единоличную собственность на объект, к которому привязан, поэтому при попытке присвоить один QScopedPointer другому произойдет ошибка компиляции. Его нельзя безопасно передавать между потоками или использовать, если требуется несколько ссылок на один объект. Пример использования: #include <QScopedPointer> void myFunction() { QScopedPointer<MyClass> ptr(new MyClass);
// Работа с объектом через ptr ptr->doSomething(); // Автоматическое освобождение памяти при выходе из функции } А вот как можно установить указатель не в момент инициализации, а в любом месте кода: QScopedPointer<MyClass> myPointer; ... myPointer.reset( new MyClass() ); // Установка указателя на созданный объект QScopedPointer поддерживает пользовательский метод удаления (deleter), что полезно для объектов, которым нужно освободить ресурсы особым образом. Указатель QSharedPointer QSharedPointer — это умный указатель Qt, обеспечивающий автоматическое управление временем жизни объекта через механизм подсчета ссылок. Основные особенности QSharedPointer включают: Подсчет ссылок и автоматическое удаление: QSharedPointer использует механизм подсчета ссылок, чтобы отслеживать количество активных копий указателя на один и тот же объект. Когда последний QSharedPointer на объект выходит из области видимости или уничтожается, объект удаляется автоматически. Совместное владение: Несколько QSharedPointer могут владеть одним и тем же объектом, безопасно управляя его временем жизни. Это полезно, когда объект должен быть доступен из нескольких мест, и необходимо убедиться, что он не будет удален, пока хотя бы один указатель ссылается на него. Потокобезопасность: QSharedPointer поддерживает потокобезопасный подсчет ссылок, что позволяет использовать его в многопоточных приложениях. Однако сами объекты, на которые он указывает, не обязательно потокобезопасны. Слабые ссылки через QWeakPointer: QWeakPointer может использоваться вместе с QSharedPointer, чтобы создать слабую ссылку на объект, не влияющую на его время жизни. Это полезно для предотвращения циклических зависимостей и утечек памяти. Функции create() и makeShared(): QSharedPointer предоставляет функцию QSharedPointer<T>::create(), которая создает и инициализирует объект прямо внутри умного указателя, избегая возможности создания нескольких QSharedPointer для одного объекта и ошибочного подсчета ссылок. Использование с кастами указателей: QSharedPointer поддерживает различные виды кастов (dynamicCast, staticCast, constCast), что упрощает работу с полиморфными объектами и позволяет выполнять безопасные преобразования. Пример использования QSharedPointer #include <QSharedPointer> #include <QDebug> class ExampleClass { public: ExampleClass() { qDebug() << "ExampleClass создан"; } ~ExampleClass() { qDebug() << "ExampleClass удалён"; } }; void exampleFunction() { QSharedPointer<ExampleClass> ptr1 = QSharedPointer<ExampleClass>::create(); { QSharedPointer<ExampleClass> ptr2 = ptr1; qDebug() << "Ссылки на объект:" << ptr1.useCount(); // Выведет: Ссылки на объект: 2 } // ptr2 выходит из области видимости, счетчик ссылок уменьшается
qDebug() << "Ссылки на объект:" << ptr1.useCount(); // Выведет: Ссылки на объект: 1 } // ptr1 выходит из области видимости, объект удаляется Когда использовать QSharedPointer:
|
|||||||
Так же в этом разделе:
|
|||||||
|
|||||||
|