|
|||||||
Как в Qt устроены умные указатели QPointer и QSharedPointer и как с ними работать
Время создания: 06.09.2024 11:19
Текстовые метки: qt, qt4, qt5, qt6, умный указатель, QPointer, QSharedPointer
Раздел: Компьютер - Программирование - Язык C++ (Си++) - Библиотека Qt - Принципы написания кода
Запись: xintrea/mytetra_syncro/master/base/172561078176a6t6j4rl/text.html на raw.github.com
|
|||||||
|
|||||||
Здесь приведен результат объяснений, которые дала небезызвестная нервная сетка по поводу того, как устроены и как работают умные указатели в Qt. Вопросы задавались по устройству QPointer и QSharedPointer. Получилась неплохая выжимка из книг/документации с объяснением сложных моментов. * * * Вопрос Объясни, как внутри устроены умные указатели QSharedPointer. Когда в программе существует несколько QSharedPointer на один и тот же объект, каким образом контролируется количество этих указателей на данный объект? Существует какой-то менеджер указателей, или все реализуется только через тот факт, что у QSharedPointer контролируемое присвоение объектов указателей? Ответ Внутреннее устройство QSharedPointer в Qt реализовано таким образом, что за счет дополнительного объекта, называемого контролируемым блоком (control block), отслеживается количество активных ссылок на управляемый объект. Этот механизм гарантирует, что объект будет автоматически удален, как только на него больше не будет ссылок. Основные компоненты QSharedPointer:
Как работает счетчик ссылок:
Контролируемый блок создается при первом QSharedPointer:
Внутренняя реализация:
QSharedPointer<MyClass> ptr1 = QSharedPointer<MyClass>::create(); создается как управляемый объект MyClass, так и контролируемый блок с инициализацией счетчика ссылок равной 1. QSharedPointer<MyClass> ptr2 = ptr1; оба указателя (ptr1 и ptr2) теперь ссылаются на один и тот же объект, а счетчик ссылок увеличивается до 2. ptr1.clear(); // Счетчик ссылок уменьшился на 1 Если в этот момент счетчик ссылок становится равным 0, управляемый объект удаляется. Нет внешнего менеджера:Все управление ссылками реализуется внутри самих объектов QSharedPointer и контролируемого блока. Нет какого-то глобального менеджера указателей или внешнего механизма отслеживания ссылок — вся логика встроена в сам QSharedPointer и его контролируемый блок. Пример:QSharedPointer<MyClass> ptr1(new MyClass()); // Создаем объект и указатель { QSharedPointer<MyClass> ptr2 = ptr1; // Счетчик ссылок увеличился до 2 } // ptr2 уничтожен, счетчик ссылок снова 1 // После выхода из области видимости ptr1 объект будет удален автоматически В этом примере счетчик ссылок увеличивается при создании второго указателя ptr2 и уменьшается при его удалении. Когда счетчик достигнет нуля, объект MyClass будет удален автоматически. Заключение:QSharedPointer использует контролируемый блок для хранения счетчика ссылок. Этот блок создается при первом создании указателя и управляет удалением объекта, когда на него больше нет активных ссылок. Управление ссылками происходит на уровне самих умных указателей, без использования глобальных менеджеров. * * * Вопрос Стоит ли в большинстве ситуаций использовать QSharedPointer вместо QPointer? Ведь в больших программах могут происходить крупные изменениия, из-за которых на один объект вначале указывает один указатель, а потом, при изменениях в коде, на него начинают указывать несколько указателей. И если программист забудет аккукратно обойтись с QPointer, то объект может быть удален раньше, чем его перестанут использовать другие участки кода с другими QPointer на тот же объект. Ответ Выбор между QSharedPointer и QPointer в Qt зависит от ситуации и характера управления объектами. Давайте рассмотрим различия между ними и подход к выбору. Различия между QSharedPointer и QPointer:
Проблема с QPointer:QPointer полезен в ситуациях, когда объект управляется вручную, и вы хотите только отслеживать его состояние, но он не контролирует время жизни объекта. Это означает, что если вы неправильно распорядитесь временем жизни объекта (например, удалите объект, когда на него еще есть активные ссылки), программа может обратиться к удаленному объекту через QPointer или другие указатели, что приведет к ошибкам. QSharedPointer в большинстве ситуаций:В вашем примере, когда программа может развиваться, и несколько частей кода могут ссылаться на один и тот же объект, использование QSharedPointer будет более безопасным решением. Это особенно важно, если:
Аргументы в пользу использования QSharedPointer:
Когда использовать QPointer:
Заключение:В большинстве ситуаций, особенно в больших проектах, где сложно точно контролировать все указатели на объект, использование QSharedPointer предпочтительнее. Оно гарантирует, что объект будет жить ровно столько, сколько это нужно, и предотвратит ошибки, связанные с преждевременным удалением объекта. Однако, если вы точно знаете, что объект управляется вручную и вам нужно просто проверять его наличие, QPointer также может быть полезен. * * * Вопрос Ты написла, что "Если объект удален где-то в коде вручную (например, через вызов delete), все QPointer, указывающие на этот объект, автоматически станут nullptr". Каким образом не свазанные друг с другом несколько QPointer, указывающие на один и тот же объект, поймут что объект был удален и примут значение nullptr? Ответ QPointer в Qt работает через специальный механизм, встроенный в класс QObject. Этот механизм позволяет нескольким QPointer, указывающим на один и тот же объект, автоматически обнулиться, когда этот объект удаляется. Вот как это происходит:
Таким образом, несколько QPointer, указывающих на один и тот же объект, не связаны между собой напрямую, но каждый из них "слушает" удаляемый объект через систему сигналов/слотов. Когда объект удаляется, каждый QPointer получает сигнал о его уничтожении и обнуляет свою ссылку. Внутренний механизм:
Это означает, что каждый QPointer работает независимо, но все они получают сигнал от удаляемого объекта благодаря встроенному в QObject механизму. * * * Вопрос Есть ли такой же механизм оповещения об уничтожении объекта в QSharedPointer (как и в QPointer)? Что произойдет, если на один и тот же объект будет создано два QSharedPointer, причем эти умные указатели будут созданы по отдельности, не используя присвоения одного к другому? Ответ Нет, у QSharedPointer нет такого же механизма оповещения об уничтожении объекта, как у QPointer. Важно различать, что QSharedPointer и QPointer решают разные задачи:
Что произойдет, если на один объект будет создано два независимых QSharedPointer:Если на один и тот же объект будет создано два отдельных QSharedPointer без использования присвоения одного к другому, произойдут следующие проблемы:
Правильное использование QSharedPointer:
QSharedPointer<YourClass> ptr1 = QSharedPointer<YourClass>::create(); QSharedPointer<YourClass> ptr2 = ptr1; // ptr2 теперь делит владение с ptr1 В этом случае оба указателя будут делить владение объектом, и объект будет удален только тогда, когда оба указателя выйдут из области видимости или будут присвоены другим объектам. Вывод:QSharedPointer не имеет механизма отслеживания "внешнего" удаления объекта, как это делает QPointer. Для правильного использования QSharedPointer важно не создавать несколько независимых указателей на один и тот же объект напрямую. Всегда используйте присвоение одного указателя другому, чтобы они корректно делили владение объектом и управляли его временем жизни. |
|||||||
Так же в этом разделе:
|
|||||||
|
|||||||
|