将 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]));
它工作得非常好。
非常感谢您提供的有用提示!
我真的学到了一些新东西。
我正试图在这样的循环中将 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]));
它工作得非常好。
非常感谢您提供的有用提示! 我真的学到了一些新东西。