2

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

  1. 对于 Qt 拥有的一切,

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

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

    • 赤裸裸地使用、存储、传递指针;
    • delete在适当的时候手动设置它们。

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

4

2 回答 2

3

首先,尽可能按价值持有事物。查看 的每次使用newmake_unique并且make_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);
  }
};

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

如果您有一个所有者的不可移动对象,请使用std::unique_ptr并移动它。QObject这是在您自己的代码周围传递动态创建的 s 的方式。您可以在将其所有权由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()信号只能在单个线程内使用。当您在另一个线程中收到有关删除对象的通知时,为时已晚:该对象已被销毁。

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

于 2017-02-06T15:52:09.873 回答
1

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

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

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

于 2017-02-05T15:48:31.853 回答