C++11智能指针和裸指针接口有安全的使用方式吗?

14

我希望在新项目中使用C++11的智能指针,但遇到了一个问题。许多现有项目仍然在其接口中使用原始指针作为参数,并且没有智能指针的接口,例如 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中的其他方法是否对scrollArea存储的指针执行操作符delete

如果Qt中的一些方法这样做,会导致内存泄漏或其他问题吗?

我查阅了最新的C++标准CD ,但没有找到相关内容。似乎这是未定义行为。

如果这样做是未定义行为和危险的,那么是否有一种安全的方式来使用智能指针与原始指针的接口?


2
如果您不确定Qt是否执行delete,那么如何确保当前没有内存泄漏? - hmjd
2
这就好比你问:“删除指针两次会造成问题吗?” - W.B.
@W.B. 我的主要目的是为这个案例找到一个解决方案。 - UniversE
@UniversE,是的,我知道。我的评论是你怎么知道是否需要显式delete对象,如果你不确定Qt是否会替你做这件事? - hmjd
@hmjd 我使用 std::shared_ptr 来避免显式使用 deleteget() 不会释放所有权,也没有其他的 std::shared_ptr 共享 QScrollArea 对象。因此,当 scrollArea 析构时,内存将被回收。我不知道为什么要关心是否显式地从 win.setCentralWidget(scrollArea.get()); 中删除对象。 - UniversE
显示剩余2条评论
6个回答

18

通常情况下,没有这样的方法。对于每个您想要使用的“遗留”接口,您必须阅读其文档,以了解它如何与所有权交互(这就是std智能指针所封装的内容)。一个对象只能由一个所有权方案管理。

特别是在Qt中,混合使用智能指针和Qt管理绝对不安全。Qt在QObject之间的父/子关系包括所有权语义(当其父项被删除时,子项也会被删除),因此您不能将其与任何其他所有权方案(例如std智能指针)安全地混合使用。

请注意,您链接到的Qt文档明确说明:“QMainWindow占据了widget指针的所有权,并在适当的时间删除它。”


3

很遗憾,如果您正在使用使用原始指针的界面,则需要查阅文档以确定该方法是否接受所提供的指针的所有权。

如果函数接受所有权,则必须调用.release()将所有权转移给函数。如果函数不接受所有权,则应使用.get()传递对象。


3
如果Qt的一些方法这样做,会导致内存泄漏或其他问题吗?
它不会引起内存泄漏,因为毕竟内存被释放了。但是,由于QT和shared_ptr都会在该内存上调用delete,您可能会得到一些很好的堆破坏(通常为UB)。
是否有一种安全的方法使用智能指针来管理原始指针的接口?
当然可以。不要让无关的实体管理相同的内存。为此,建议在可能的情况下使用unique_ptr而不是shared_ptr。使用unique_ptr,您可以调用.release()来释放智能指针对内存的控制权,从而使您能够将控制权交给QT。
当然,您需要检查文档以查看何时必须自行管理内存以及何时QT会为您管理内存。

3

3

如果您正在使用接受原始指针的接口,那么您已经面临一个问题,即您必须知道谁负责这些指针的生命周期。

添加shared_ptr并没有改变这一点。

如果接口可能会删除对象,则无法安全地使用std::shared_ptrstd::shared_ptr 必须控制其对象的生命周期,没有其他方法可以解决此问题(除非添加另一层间接性)

但是,您可以从std::unique_ptr中获得一些用处。如果接口不会删除指针,则可以安全地传递ptr.get()。如果接口接管了该对象的生命周期,请传递ptr.release()并放弃自己控制生命周期。

总之,即使在遗留代码库中,您也可以从智能指针中获得一些有用的东西,但必须小心谨慎。


1

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

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接