首页 > 解决方案 > Qt - 保持指向存储在 QList 中的内容的指针的最佳方法是什么?

问题描述

我对 Qt 和 C++ 很陌生(我一生都在研究 C# 和 Java),而且我几乎在所有地方都在阅读我不应该再使用原始指针(除了构造函数和析构函数中的指针,遵循 RAII 原则)。

我可以接受,但是有一个问题,如果没有指针,我无法轻松解决。

我会试着解释我的问题。

我正在创建一个由我创建的自定义类(MyClass)的 QList,它将充当我的应用程序的模型:

QList<MyClass> modelList;

该 QList 由工作线程根据来自网络的信息进行更新(添加、删除或更新项目)。

到目前为止,一切都很好。

现在我有另一个线程(GUI 线程),它有一个可绘制项目的 QList(MyDrawableItem)。这些项目中的每一个都有一个成员,该成员必须指向第一个 QList (modelList) 中的一个项目,如下所示:

QList<MyDrawableItem> listToDraw;

在哪里:

class MyDrawableItem
{
private:
    MyObject *pointedObject;

    //List of many other members related to drawing
}

因为每次 GUI 线程中的计时器到期时,我都必须根据指向的对象更新绘图相关成员。必须注意,保持指向 QList 成员的指针是安全的,如文档中所述:

注意:只要引用的项目保留在容器中,指向 QLinkedList 的迭代器和对堆分配 QList 的引用仍然有效。这不适用于迭代器和对 QVector 和非堆分配 QLists 的引用。

在内部,如果 sizeof(T) <= sizeof(void*) 并且 T 已使用 Q_DECLARE_TYPEINFO 声明为 Q_MOVABLE_TYPE 或 Q_PRIMITIVE_TYPE,则 QList 表示为 T 的数组。否则,QList 表示为 T* 数组,并且项目在堆上分配。

如果不使用指针,这怎么可能可行?或者更好的是,做这种工作的最好方法是什么?

我找到了三种可能的解决方案:

  1. 与其将pointedObject 保留为MyDrawableItem 的成员,不如将pointedObject 的索引保留在modelList 中。然后在更新中查看 QList 内部。但是如果列表中的项目被删除了怎么办?我可以发出信号,但如果更新发生在调用插槽之前?

  2. 根本不要保留任何东西作为成员,并将两个信号连接到 MyDrawableItem。一个信号是updateDrawing(const MyObject&)更新与绘图相关的成员,另一个信号是removeDrawing()简单地删除对象。这样我就不必担心线程之间的同步,因为 MyDrawableItem 对象永远不会查看 QList 的内容。在这种情况下,我可能会经常使用大量信号更新项目,而我只想偶尔更新一次 GUI(500 毫秒的计时器)。

  3. 只需使用指针。

  4. 发展并使用 QSharedPointers,但我从未使用过这些,我不知道这是否是最佳选择。

我认为这些解决方案都不是完美的,所以我在这里寻求您的帮助。

Qt 中的标准视图(tableview、listview、ecc.)如何处理这个问题?

我应该如何处理?

请帮帮我,我从昨天开始就在想这个,我不想弄得一团糟。

非常感谢!

标签: c++qt

解决方案


@Benjamin T 答案的补充:

如果您决定选择选项 4 并使用QSharedPointer(或 std 变体),您实际上可以使用“弱指针”在一定程度上控制所有权。弱指针存储对对象的引用,但不拥有它。一旦最后一个“强指针”被销毁,所有弱指针都会放弃引用并将自己重置为nullptr.

对于您的具体示例,您可以将 aQList<QSharedPointer<MyClass>>用于模型并QWeakPointer<MyClass>在可绘制类中使用。在绘图之前,您将在绘图函数中创建一个局部QSharedPointer<MyClass>并检查它是否有效。

我仍然建议您按照 Benjamin 的建议使用 2/3。只是一个小小的补充。


推荐阅读