【问题标题】:Is there a safe way to use C++11 Smart Pointer and the Interface for Raw Pointer together?有没有一种安全的方法可以同时使用 C++11 智能指针和原始指针接口?
【发布时间】:2023-03-19 15:48:02
【问题描述】:

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

如果这样做是一种未定义的行为并且很危险,是否有一种安全的方法可以将智能指针与原始指针接口一起使用?

【问题讨论】:

  • 如果你不确定Qt是否执行delete你如何确保当前没有内存泄漏?
  • 这和你问“两次删除指针会不会出问题”是一样的
  • @W.B.我的主要目的是为这种情况找到解决方案。
  • @hmjd 当然目前没有内存泄漏。你不知道std::shared_ptr 是做什么的吗?
  • @UniversE,是的,我愿意。我的评论是,如果您不知道 Qt 是否为您执行此操作,那么您目前如何知道是否明确 delete 对象?

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


【解决方案1】:

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

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

请注意,您链接到的 Qt 文档明确声明“QMainWindow 拥有 widget 指针的所有权并在适当的时候将其删除。”

【讨论】:

    【解决方案2】:

    不幸的是,如果您使用的接口使用原始指针,则需要查阅文档以确定该方法是否拥有所提供指针的所有权。

    如果函数取得所有权,那么您必须调用.release() 将所有权转移给函数。如果函数没有所有权,那么您将使用.get() 传递对象。

    【讨论】:

      【解决方案3】:

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

      它不会引入内存泄漏,因为内存毕竟是释放的。但是,由于 QT 和 shared_ptr 都会在该内存上调用 delete,因此您可能会遇到一些不错的堆损坏(通常是 UB)。

      有没有一种安全的方式来使用智能指针和原始指针接口?

      当然。不要让不相关的实体管理相同的内存。为此,尽可能使用unique_ptr 而不是shared_ptr。使用unique_ptr,您可以调用.release() 从智能指针的控制中释放内存,从而使您能够将控制权交给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 指针执行 operator delete。

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

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2019-06-30
              • 1970-01-01
              • 1970-01-01
              • 2014-11-22
              • 1970-01-01
              • 2023-01-08
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多