Почему официальные примеры и учебники Qt не используют интеллектуальные указатели?


почему официальные примеры и учебники о библиотеке Qt не использовать смарт-указатели? Я вижу только new и delete для создания и уничтожения виджеты.

Я искал обоснование, но я не мог его найти, и я не вижу его сам, за исключением того, что это по историческим причинам или обратной совместимости: не все хотят, чтобы программа завершалась, если конструктор виджета терпит неудачу, и обработка его с помощью блоков try/catch просто уродлива (даже если используется в нескольких местах). Тот факт, что родительские виджеты могут взять на себя ответственность за детей, также только частично объясняет мне это, так как вам все равно придется использовать delete для родителей на каком-то уровне.

5 60

5 ответов:

потому что Qt использует родительско-дочернюю модель для управления ресурсами Qobject. Он следует шаблону composite + Chain-of-responsibility, который используется от управления событиями до управления памятью, рисования, обработки файлов и т. д...

на самом деле, пытаясь использовать QObject в общем\уникальный указатель - это чрезмерное усложнение (99% времени).

  1. вы должны предоставить пользовательский делетер, который будет вызывать deleteLater
  2. ваш qobject с родителями уже есть ссылка в Родительском объекте. Таким образом, вы знаете, что объект не просочился, пока существует родитель. Когда вам нужно избавиться от него, вы можете позвонить deleteLater напрямую.
  3. у вашего QWidget без родителя уже есть ссылка в объекте Qapplication. Так же как и пункт 2.

тем не менее, вы все еще можете использовать RAII с Qt. Например,QPointer ведет себя как слабая ссылка на A QObject. Я бы использовал QPointer<QWidget> а чем QWidget*.

Примечание : чтобы не звучать слишком фанатом, два слова: Qt + valgrind.

умные указатели для детей

классы интеллектуальных указателей std::unique_ptr и std::shared_ptr для управления памятью. Наличие такого умного указателя означает, что вы собственные указатель. Однако, при создании QObject или производный тип с QObject родитель, право собственности (ответственность за уборку) передается родителю QObject. В этом случае стандартные интеллектуальные указатели библиотеки являются ненужными или даже опасными, поскольку они потенциально могут вызвать двойное удаление. Фу!

сырые указатели для детей-сирот

однако, когда a QObject (или производный тип) создается в куче без родительского QObject все очень по-другому. В этом случае вы должны не просто держать необработанный указатель, а умный указатель, предпочтительно std::unique_ptr на объект. Таким образом, вы получаете безопасность ресурсов. Если вы позже передадите право собственности на объект родительскому QObject можно использовать std::unique_ptr<T>::release(), например:

auto obj = std::make_unique<MyObject>();
// ... do some stuff that might throw ...
QObject parentObject;
obj->setParent( &parentObject );
obj.release();

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

в целом

это не современный Совет C++, чтобы избежать необработанных указателей все вместе, но чтобы избежать владеющего сырые указатели. Я мог бы добавить еще один современный Совет C++:не используйте интеллектуальные указатели для объектов, принадлежащих какой-либо другой программе сущность.

вы уже ответили на свой вопрос : except if it's for historic reasons/backward compatibility. Библиотека, которая так же огромна, как QT, не может предположить, что все, кто использует библиотеку, имеют компиляторы, поддерживающие C++11. new и delete гарантированно существуют в более ранних стандартах.

однако, если у вас есть поддержка для использования интеллектуальных указателей, я бы рекомендовал использовать их поверх необработанных указателей.

в дополнение к тому, что @Jamey сказал:

Если вы создадите его умно, вам никогда не придется использовать удаление на виджете. Допустим, у вас есть главное окно, и вы создаете его автоматический объект и запускаете это окно в цикле событий. Теперь остальные все элементы в этом виджете могут быть добавлены как его дочерние элементы. И поскольку вы добавляете их в это главное окно прямо / косвенно как ребенок, когда вы закроете это главное окно, все будет сделано автоматически. Просто вы должны убедитесь, что все динамические объекты / виджеты, которые вы создали, являются детьми / внуками главного окна. Следовательно, нет необходимости в явном удалении..

  • QObject имеет определенный родитель и древовидную структуру программа позволяет достаточно эффективно управлять памятью.

  • динамизм в Qt нарушает этот хороший идеал,например, передавая необработанный указатель. Можно легко в конечном итоге провести dangling pointer, но это обычная проблема в программировании.

  • интеллектуальный указатель Qt, на самом деле слабая ссылка, является QPointer<T>
    и предоставляет некоторые из STL конфета.

  • можно также смешивать с std::unique_ptr и тому подобное , но это должно используйте только для машин не-Qt в вашей программе.