Подтвердить что ты не робот

Есть ли безопасный способ использования С++ 11 Smart Pointer и интерфейса для Raw Pointer вместе?

Я хочу использовать С++ 11 Smart Pointers в новых проектах и ​​сталкиваться с проблемой. Многие текущие проекты по-прежнему используют исходные указатели в качестве параметров в своем интерфейсе и не имеют интерфейса для интеллектуальных указателей, например. QMainWindow:: setCentralWidget.

Чтобы сохранить тип согласованным, я должен передать сохраненный указатель из get(), как этот сегмент:

QMainWindow win;

std::shared_ptr<QWidget> scrollArea{ std::make_shared<QScrollArea>() };
// QScrollArea is a derived class of QWidget.

win.setCentralWidget(scrollArea.get());

Но я не могу убедиться, что другие методы в Qt выполняют оператор delete на сохраненном указателе scrollArea.

Может ли это вызвать утечку памяти или другие проблемы, если некоторые методы в Qt делают это?

Я проверил последний С++ Standard CD и ничего не нашел. Кажется, это поведение undefined.

Если это поведение undefined и опасно, существует ли безопасный способ использования интеллектуальных указателей (ов) с интерфейсом для необработанных указателей?

4b9b3361

Ответ 1

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

В частности, Qt, безусловно, небезопасно смешивать интеллектуальные указатели и управление Qt. Роль/дочерние отношения Qt между QObject включает семантику собственности (дети удаляются, когда их родитель), поэтому вы не можете смело смешивать это с любой другой схемой собственности (например, std умные указатели).

Обратите внимание, что ссылки Qt, на которые вы ссылаетесь, явно указываете, что "QMainWindow получает право собственности на указатель виджета и удаляет его в соответствующее время".

Ответ 2

К сожалению, если вы используете интерфейс, который использует необработанные указатели, вам нужно будет проконсультироваться с документацией, чтобы определить, принадлежит ли этот метод или не принадлежит владельцу предоставленного указателя.

Если функция переходит в собственность, вы должны вызвать .release(), чтобы передать право собственности на эту функцию. Если функция не переходит в собственность, вы должны передать объект с помощью .get().

Ответ 3

Может ли это вызвать утечку памяти или другие проблемы, если некоторые методы в Qt делают это?

Это не приведет к утечке памяти, так как память после этого будет выпущена. Однако, так как QT и shared_ptr будут вызывать delete в этой памяти, вы, вероятно, получите некоторое повреждение кучи (UB в целом).

существует ли безопасный способ использования интеллектуальных указателей (ов) с интерфейсом для необработанных указателей (ов)?

Конечно. Не иметь несвязанных сущностей, управляющих одной и той же памятью. Для этого рекомендуется использовать unique_ptr вместо shared_ptr, когда это возможно. С помощью unique_ptr вы можете вызвать .release(), чтобы освободить память от элемента управления smartpointer, тем самым предоставив вам возможность управлять QT.

Конечно, вам нужно проверить документацию, чтобы увидеть, когда вам нужно самостоятельно управлять памятью, и когда QT сделает это за вас.

Ответ 4

Я не думаю, что вы должны удалять QWidget.

http://qt-project.org/doc/qt-4.8/qmainwindow.html#setCentralWidget

Примечание. QMainWindow берет на себя ответственность за указатель виджета и удаляет его в соответствующее время.

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

Ответ 5

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

Добавление shared_ptr в микс не меняет этого.

Если интерфейс, возможно, удалит объект, вы не сможете безопасно использовать std::shared_ptr. std::shared_ptr должен контролировать время жизни своих объектов, и нет никакого пути вокруг этого (без добавления другого уровня косвенности)

Однако вы можете использовать некоторые из std::unique_ptr. Если интерфейс не удаляет указатель, вы можете безопасно пройти в ptr.get(). Если интерфейс принимает на себя ответственность за время жизни этого объекта, пройдите в ptr.release(), и вы сами откажетесь контролировать время жизни.

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

Ответ 6

Но я не могу проверить, удаляются ли другие методы в операторе выполнения Qt на сохраненном указателе scrollArea.

Если у виджета есть родительский элемент, тогда управление памятью QT освободит этот объект. В этом случае вы не должны использовать интеллектуальный указатель, потому что ваше приложение будет пытаться выпустить его дважды, и это поведение undefined.