我应该如何在 Qt 中存储指针?

sig*_*gil 3 c++ qt pointers qpointer

我的宠物项目已经到了我应该开始跟踪指针寿命的地步,我正在尝试为其开发一些系统。遗憾的是,流行的到处使用智能指针的建议并不适用,因为 Qt API 本身在任何情况下都使用裸指针。所以,我想到的是:

  1. 对于 Qt 拥有的一切,

    • 本地使用裸指针;
    • 也可以在函数之间传递它们;
    • 将它们存储为子类QPointer,在转换为裸之前进行isNull()检查。
  2. 对于我完全拥有的所有东西,请按照建议使用智能指针。我将使用std::这里的版本。

  3. 令我烦恼的案子。对于切换所有权的对象(例如从布局中添加/删除的小部件)

    • 裸露地使用、存储、传递指针;
    • delete在适当的时候手动进行。

建议、意见、建议?我自己不太喜欢这个方案。

Rei*_*ica 5

首先,尽可能按价值持有事物。带着怀疑的态度查看 的new每次使用- 您必须证明每个动态对象创建的合理性。如果子对象与父对象具有相同的生命周期,则按值保存是理所当然的。例如:make_uniquemake_shared

class MyWidget : public QWidget {
  Q_OBJECT
  QGridLayout m_topLayout{this};
  QLabel m_sign{"Hello World"};
public:
  MyWidget(QWidget * parent = nullptr) : QWidget{parent} {
    m_topLayout.addWidget(&m_sign, 0, 0);
  }
};
Run Code Online (Sandbox Code Playgroud)

您正在传递指针,但对象所有权是明确的,并且所有权没有变化。仅仅因为 aQObject有父对象并不意味着父对象“拥有”它。如果孩子在父母之前被摧毁,则所有权终止。通过使用 C++ 语义(即成员构造和销毁的明确定义的顺序),您可以完全控制子生命周期,并且QObject父级无法干涉。

如果您有一个只有一个所有者的不可移动物体,请使用std::unique_ptr并移动它。这是在您自己的代码中传递动态创建的方法QObjectQObject您可以在将其所有权由父级(如果有)管理时将它们从指针中删除。

如果您有共享所有权的对象,并且它们的生命周期应尽快结束(相对于应用程序终止或某些长期存在的对象被销毁时),请使用std::shared_ptr. 确保指针的寿命比用户的寿命长。例如:

class MyData : public QAbstractItemModel { /* ... */ };

class UserWindow : public QWidget {
  Q_OBJECT
  std::shared_ptr<MyData> m_data; // guaranteed to outlive the view
  QTreeView m_view;
public:
  void setData(std::shared_ptr<MyData> && data) {
    m_data = std::move(data);
    m_view.setModel(m_data.data());
  }
};
Run Code Online (Sandbox Code Playgroud)

这个例子可能是人为的,因为在 Qt 中大多数对象用户都会观察对象的destroyed()信号并对对象的销毁做出反应。m_view但是,如果eg是无法跟踪数据对象生命周期的第三方C API 对象句柄,则这是有意义的。

如果对象的所有权是跨线程共享的,那么使用std::shared_ptr是必不可少的:destroyed()信号只能在单个线程中使用。当您在另一个线程中收到有关对象删除的通知时,为时已晚:该对象已经被销毁。

第三,当您从工厂方法返回动态创建的对象的实例时,您应该通过裸指针返回它们:很明显,工厂创建一个对象供其他人管理。如果你需要异常安全,你可以返回 astd::unique_ptr来代替。