将 Qt 对象 (QgraphicsItem) 转换为 C++ class 对象的最佳方法是什么

what is the best way to convert a Qt object(QgraphicsItem) into C++ class object

我正试图在这样的循环中将 Qt 对象转换为 C++ class 对象

std::vector<PBWMPlugDeviceGraphicsItem*> deviceItms;

for(int i=0; i<fScene->items().size(); i++)
    deviceItms.push_back(dynamic_cast<PBWMPlugDeviceGraphicsItem*>(fScene->items().at(i)));

其中 PBWMPlugDeviceGraphicsItem 是 C++ class。似乎,当总没有。项目的数量大于某个阈值(例如 fScene->items().size() >900),转换这些对象需要花费大量时间,因此我可以看到 QGraphicsScene 上的操作非常慢。我读到 dynamic_cast 有严重的性能问题。

还有其他great/fast方法可以达到同样的效果吗?

谢谢!

使用这个:

for (auto p: fScene->items())
    deviceItms.push_back(dynamic_cast<PBWMPlugDeviceGraphicsItem*>(p));

两个重要区别:

  • 它只调用 fScene->items() 一次。除非该函数 returns 通过 (const) 引用,否则为每次迭代检索和丢弃容器是无用的开销,特别是如果内容不应该在迭代之间更改时。
  • 它没有使用索引并在 at() 中验证该索引,而是使用 C++11 for 循环和自动类型变量。 at() 仅在您怀疑索引是否有效时有用(例如,当它从用户输入时),但如果您不能编写简单的循环,那么您确实有更重要的问题。

使用vector::reserve()预分配内存的第三次优化我没有走。如果您真的只有几个对象(是的,900 个很少),那么它可能很难被注意到。不过,请对此进行一些研究,因为它是您应该了解的工具。

for(int i=0; i<fScene->items().size(); i++)
  deviceItms.push_back(dynamic_cast<PBWMPlugDeviceGraphicsItem*>(fScene->items().at(i)));

根据评论回复,似乎 fScene->items() returns 类似于 QList<QGraphicsItem *>

在编写代码时,会在每次循环迭代时创建和丢弃此 QList 的实例。因此,作为第一个优化,我会尝试在循环 外部 获取该列表 once,然后在循环内处理相同的实例,避免浪费每次循环迭代时列表的 creation/destruction。

如果您可以使用 C++11,我同意@Ulrich 关于使用基于范围的 for 循环的建议:这将使代码 更简单 更快.


编辑

您在此处的评论中写道,您不能使用 C++11,因此无法享受基于范围的 for 循环。
那么,替代方案可能是:

// Get the collection of items once, outside the loop
QList<QGraphicsItem *> items = fScene->items();

// For each graphics item in the collection...
for (int i = 0; i < items.size(); i++) {
    deviceItems.push_back(dynamic_cast<PBWMPlugDeviceGraphicsItem*>(items.at(i)));
}

问题是调用 QList::at,它 returns 引用列表项,导致 QList 进行写时复制分离。

最小的解决方案是调用 QList::value 来获取指针,而不是 at

其他解决方案是获取列表一次,如其他答案中所述。这样即使您使用 at.

分离也只会发生一次

您还可以通过强制转换或临时变量强制使用 at 的 const 版本。

谢谢大家! 你的建议很有用。我按以下方式实现(因为我不能使用 C++11)

        QList<QGraphicsItem*> temp= fScene->items();
    for(int i=0; i<temp.size(); i++)
        deviceItms.push_back(dynamic_cast<PBWMPlugDeviceGraphicsItem*>(temp[i]));

它工作得非常好。

非常感谢您提供的有用提示! 我真的学到了一些新东西。