有没有一种安全的方法可以将C ++ 11智能指针和原始指针接口一起使用?

时间:2013-05-21 07:48:22

标签: c++ qt c++11 interface smart-pointers

我想在新项目中使用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,但没有发现任何内容。似乎这是一种未定义的行为。

如果执行此操作是未定义的行为并且存在危险,是否有一种安全的方法可以将智能指针与原始指针的接口一起使用?

6 个答案:

答案 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_ptrstd::shared_ptr必须控制其对象的生命周期,并且无法解决此问题(不添加其他级别的间接)

然而,您可以使用std::unique_ptr。如果界面不会删除指针,您可以安全地传入ptr.get()。如果某个接口取得该对象生命周期的所有权,请传入ptr.release()并放弃控制生命周期。

全部,即使使用遗留代码库,您也可以通过智能指针获得一些实用性,但是您必须要小心。

答案 5 :(得分:1)

  

但我无法确定Qt中的其他方法是否对存储的scrollArea指针执行operator delete。

如果窗口小部件有父窗口,那么QT的内存管理将释放该对象。在这种情况下,您不能使用智能指针,因为您的应用程序将尝试释放它两次,这是一种未定义的行为。