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

时间:2017-02-05 15:05:26

标签: c++ qt pointers qpointer

我的宠物项目已经到了我应该开始跟踪指针生命周期的地步,我正在尝试为它开发一些系统。遗憾的是,由于Qt API本身在每个场合都使用裸指针,所以在各地都使用智能指针的流行建议并不适用。所以,我想出的是:

  1. 对于Qt所拥有的一切,

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

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

    • 使用,存储,传递赤裸的指针;
    • delete在适当的时候手动。
  4. 建议,意见,建议?我自己并不喜欢这个计划。

2 个答案:

答案 0 :(得分:2)

首先,尽可能按值保存。查看newmake_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);
  }
};

你正在传递指针,但对象所有权是明确的,并且所有权没有变化。 仅仅因为QObject有父母并不意味着父母“拥有”它。如果孩子在父母之前遭到破坏,则所有权停止。通过使用C ++语义 - 即明确定义的成员构造和破坏顺序 - 您可以完全控制子生存期,并且QObject父级不会干扰。

如果您有一个拥有一个所有者的不可移动对象,请使用std::unique_ptr并移动它。这是在您自己的代码周围传递动态创建的QObject的方法。您可以在QObject父级管理其所有权的位置从指针中删除它们,如果有的话。

如果您拥有共享所有权的对象,其生命应该尽快结束(与应用程序终止时相比,或者某些长期存在的对象被破坏),请使用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());
  }
};

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

如果对象的所有权是跨线程共享的,那么使用std::shared_ptr是必不可少的:destroyed()信号只能在单个线程中使用。当你在另一个线程中获知有关对象删除的消息时,为时已晚:该对象已被破坏。

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

答案 1 :(得分:1)

对于首发,在罗马,是罗马人 QT是在90年代初期开发的,并且一次取得了巨大的成功 不幸的是,随着时间的推移,QT并没有真正采用新功能,因此API本身具有非常古老的C ++风格(我可以说,它是一种Java风格吗?)

你不能强迫QT突然变成C ++ 14,因为它不是。在QT方面使用流行的QT约定。如果这是平台设计目标,请使用原始指针。你可以使用价值类型。

但我不认为你使用C ++ 14让QT工作得那么多。坚持平台给出的QT习语。