Что произойдет, если объект, удерживаемый умным указателем, будет удален в другом месте? - PullRequest
12 голосов
/ 03 марта 2012

Этот вопрос всегда беспокоит меня, особенно когда я программирую на Qt. Поскольку Qt использует деревья владения объектами, передача указателя, например, через myBoostSharedPtr.get() можно неявно передать право собственности. Теперь рассмотрим случай, когда некоторый объект Qt уничтожается и все дерево объектов уничтожается, а смарт-указатель все еще жив, например как член другого класса. Что произойдет, если смарт-указатель впоследствии будет удален? Двойное удаление со всеми неприятными последствиями? Какие-нибудь реализации интеллектуальных указателей предотвращают это?

Ответы [ 3 ]

18 голосов
/ 03 марта 2012

Мне так хочется разглагольствовать по слабым сторонам модели памяти Qt, где многие API все еще принимают необработанные указатели, ожидая, что клиент выделит их, в то время как QObject, принявший указатель, удалит его.

Ответ на ваш вопрос: неопределенное поведение .shared_ptr не имеет механизма, позволяющего определить, был ли удален указатель чем-либо, кроме самого shared_ptr, поэтому обычно он пытается освободить указатель во второй раз (вызывая delete для висящего указателя).Если вы хотите использовать shared_ptr, вы должны придерживаться shared_ptr в качестве единственного менеджера памяти.Это верно даже для собственной QSharedPointer.

в Qt. То, что я обычно делал, чтобы попытаться сделать мой код достаточно безопасным для исключений при использовании чего-то вроде Qt, заключалось в использовании устаревшей auto_ptr (unique_ptr заменяетэто намного безопаснее, если у вас есть C ++ 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 уничтожается с помощью сигнала уничтожения, и избегать попытки удаления объекта во второй раз.Тем не менее, это может вызывать беспокойство, полагаясь на этот сигнал в многопоточном коде, и если вы реализуете общий указатель, это может стать довольно тяжелым бременем для атомного подсчета ссылок, захвата функции удаления на месте, где создан указатель (чтобы избежать модуляграницы новые / удалить несоответствия) и т. д.

1 голос
/ 03 марта 2012

Вы не можете совместно владеть родительским QObject и умным указателем и не можете удалить одно из них другим, но вы можете отслеживать удаление любого QObject, используя только QWeakPointer (или QPointer).

См. http://qt -project.org / doc / qt-4.8 / qweakpointer.html # tracking-qobject

Обновление : сQt 5, отслеживание QObject s, не управляемое QSharedPointer с QWeakPointer, устарело в пользу QPointer (которое само по себе устарело ).

1 голос
/ 03 марта 2012

Да, скорее всего, Нет, нет, и я не вижу, как они могли.Вы должны полагаться на контракт, что объект, на который вы передаете указатель, не станет владельцем (если это не указано в документации), и если последний, не заключайте его в умный указатель на вашей стороне.

...