Ответ 1
Я настолько соблазнился, чтобы рассказать о слабых сторонах модели памяти Qt, где многие API по-прежнему принимают необработанные указатели с ожиданием, что клиент выделяет его, а QObject, который принял указатель, удаляет его.
Ответ на ваш вопрос - поведение undefined. shared_ptr
не имеет механизма для обнаружения, если указатель удаляется чем-то другим, кроме самого shared_ptr, поэтому он обычно пытается освободить указатель во второй раз (вызов delete на висящем указателе). Если вы хотите использовать shared_ptr, вы должны придерживаться shared_ptr как единственного менеджера памяти. Это справедливо даже для Qt собственного QSharedPointer
.
Что я обычно делал, чтобы попытаться сделать код безопасным для использования при использовании чего-то вроде Qt, чтобы использовать теперь устаревший auto_ptr
(unique_ptr
заменяет его и гораздо безопаснее, если у вас есть С++ 11), Это единственное место, где я когда-либо испытывал желание использовать auto_ptr
раньше, поскольку он предоставляет метод release
.
unique_ptr<QListWidget> widget(new QListWidget(...));
// do stuff with the widget to set it up for your GUI
some_layout.addWidget(widget.release()); // <-- release ownership so that
// the layout now becomes responsible
// for memory management
// ^^ auto_ptr works above if we don't have C++11
Если вам нужно сохранить постоянный указатель на свой объект после того, как он уже управляется памятью с помощью Qt (например: указатель на ваш виджет после того, как вы вставили его в макет), просто используйте обычный указатель. Там не намного лучше вы можете сделать, так как Qt теперь является менеджером памяти для этого объекта.
Однако вы можете обнаружить, когда объект уничтожен (и, следовательно, когда указатель недействителен) через сигнал QObject::destroyed
.
Если вы хотите получить действительно сложный, вы можете создать общий тип указателя, который хранит только подклассы QObject. Поскольку QObject предоставляет разрушенный сигнал, этот вид пользовательского интеллектуального указателя может обнаруживать, когда QObject уничтожается через сигнал уничтожения и не пытается удалить объект во второй раз. Тем не менее, он может получить волосатый, полагающийся на этот сигнал в многопоточном коде, и если вы реализуете общий указатель, это может стать довольно сложной задачей, связанной с подсчетом атомных ссылок, захватом функции удаления на сайте, который создается указатель (чтобы избежать модуля граничные новые/исключающие несоответствия) и т.д.