我想在新项目中使用C ++ 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中的某些方法会导致内存泄漏或其他问题吗?
我查看了最新的C++ Standard CD,但没有发现任何内容。似乎这是一种未定义的行为。
如果执行此操作是未定义的行为并且存在危险,是否有一种安全的方法可以将智能指针与原始指针的接口一起使用?
答案 0 :(得分:16)
一般情况下没有这种方式。对于您要使用的每个“遗留”接口,您必须阅读其文档以了解它与所有权的交互方式(这是std
智能指针封装的内容)。单个对象只能由一个所有权方案管理。
特别是Qt,混合智能指针和Qt管理肯定不安全。 Qt在QObject
之间的父/子关系包括所有权语义(当父项为子项时将删除子项),因此您无法安全地将其与任何其他所有权方案(例如std
智能指针)混合使用。
请注意,您链接的Qt文档明确声明“QMainWindow
获取小部件指针的所有权并在适当的时候删除它。”
答案 1 :(得分:3)
不幸的是,如果您使用的是使用原始指针的接口,则需要查阅文档以确定该方法是否取得了所提供指针的所有权。
如果该函数取得所有权,则必须调用.release()
将所有权转移给该函数。如果该函数没有获得所有权,那么您将使用.get()
传递该对象。
答案 2 :(得分:3)
如果Qt中的某些方法会导致内存泄漏或其他问题吗?
它不会引入内存泄漏,因为内存已经完全释放。但是,由于QT和shared_ptr
都会在该内存上调用delete
,因此您可能会获得一些不错的堆损坏(通常是UB)。
有没有一种安全的方法可以使用带有原始指针接口的智能指针?
不确定。没有不相关的实体管理相同的内存。为此,尽可能使用unique_ptr
代替shared_ptr
是很有意义的。使用unique_ptr
,您可以调用.release()
从智能指针的控制中释放内存,从而使您能够控制QT。
当然,您需要查看文档,了解何时需要自己管理内存以及QT何时为您执行此操作。
答案 3 :(得分:3)
我认为您不应该使用QWidget进行任何删除。
http://qt-project.org/doc/qt-4.8/qmainwindow.html#setCentralWidget
注意:QMainWindow获取小部件指针的所有权并删除它 在适当的时候。
如果你必须使用智能指针,你可以使用不会拥有或销毁它的weak_ptr。
答案 4 :(得分:3)
如果您使用的是接受原始指针的接口,那么您已经遇到了必须知道谁负责这些指针的生命周期的问题。
将shared_ptr添加到混音中不会改变这一点。
如果界面可能删除该对象,则无法安全使用std::shared_ptr
。 std::shared_ptr
必须控制其对象的生命周期,并且无法解决此问题(不添加其他级别的间接)
然而,您可以使用std::unique_ptr
。如果界面不会删除指针,您可以安全地传入ptr.get()
。如果某个接口取得该对象生命周期的所有权,请传入ptr.release()
并放弃控制生命周期。
全部,即使使用遗留代码库,您也可以通过智能指针获得一些实用性,但是您必须要小心。
答案 5 :(得分:1)
但我无法确定Qt中的其他方法是否对存储的scrollArea指针执行operator delete。
如果窗口小部件有父窗口,那么QT的内存管理将释放该对象。在这种情况下,您不能使用智能指针,因为您的应用程序将尝试释放它两次,这是一种未定义的行为。