【问题标题】:std::map performance c++std::map 性能 C++
【发布时间】:2012-12-04 12:22:58
【问题描述】:

我的 std::map 性能有问题。在我的 C++ 项目中,我有一个 GUIObjects 列表,其中还包括 Windows。我在for 循环中绘制所有内容,如下所示:

unsigned int guiObjectListSize = m_guiObjectList.size();
for(unsigned int i = 0; i < guiObjectListSize; i++)
{
    GUIObject* obj = m_guiObjectList[i];
    if(obj->getParentId() < 0)
    obj->draw();                                
}

在这种情况下,当我运行一个项目时,它运行顺利。我有 4 个窗口和一些其他组件,如按钮等。

但是我想单独处理绘制窗口,所以修改后我的代码如下:

// Draw all objects except windows
unsigned int guiObjectListSize = m_guiObjectList.size();
for(unsigned int i = 0; i < guiObjectListSize; i++)
{
    GUIObject* obj = m_guiObjectList[i];
    if((obj->getParentId() < 0) && (dynamic_cast<Window*>(obj) == nullptr))
        obj->draw();        // GUIManager should only draw objects which don't have parents specified
                            // And those that aren't instances of Window class
                            // Rest objects will be drawn by their parents
                            // But only if that parent is able to draw children (i.e. Window or Layout)
}

// Now draw windows
for(int i = 1; i <= m_windowList.size(); i++)
{
    m_windowList[i]->draw(); // m_windowList is a map!
}

所以我创建了一个std::map&lt;int, Window*&gt;,因为我需要在地图中将Windows 的z-index 设置为keys。但问题是当我运行这段代码时,它真的很慢。尽管我只有 4 个窗口(地图大小为 4),但我可以看到 fps 速率非常低。我不能说一个确切的数字,因为我还没有实现这样的计数器。

谁能告诉我为什么这种方法这么慢?

【问题讨论】:

  • 你确定不是dynamic_cast慢吗?
  • 避免 dynamic_cast,尤其是在循环中
  • @Agentlien 是的,我尝试在 if 语句中删除此 dynamic_cast 条件并保留地图内容绘制(因此绘制了 2 倍以上的窗口,但这个数字 8 并不是很大) ,但还是很慢。
  • 使用分析器并查看实际瓶颈在哪里
  • 为什么m_windowList 是地图?您正在按整数而不是更复杂的东西进行索引,并且索引很密集(显然从 1 到 size()-1,包括在内)。这表明一个向量或一个双端队列。使用向量,您的 m_windowList[i] 是 O(1) 操作。使用地图,这是一个 O(log(n)) 操作。

标签: c++ stl map containers


【解决方案1】:

这就是虚函数的用途。您不仅消除了缓慢的dynamic_cast,而且还获得了更灵活的类型检查。

// Draw all objects except windows
unsigned int guiObjectListSize = m_guiObjectList.size();
for(unsigned int i = 0; i < guiObjectListSize; i++)
{
    GUIObject* obj = m_guiObjectList[i];
    if(obj->getParentId() < 0)
        obj->drawFirstChance();
}

// Now draw windows
for(int i = 1; i <= m_windowList.size(); i++)
{
    m_windowList[i]->drawSecondChance();
}

drawFirstChance 对窗口和其他浮动对象没有任何作用。

下一个优化机会是将窗口列表设为vector,并仅在其更改时执行 z 顺序排序(假设创建/销毁/重新排序窗口的频率远低于绘制窗口的频率)。

【讨论】:

    【解决方案2】:

    这段代码的问题似乎与使用 std::map 无关。相反,瓶颈在于使用dynamic_cast,这是一个非常昂贵的操作,因为它需要遍历给定类的继承树。

    对于您的 GUI 组件来说,这棵树很可能相当大,这肯定可以解释为什么在每次迭代中这样做会减慢整个方法的速度。

    【讨论】:

    • 感谢 Agentlien 的回答,但正如我回复您的评论一样 - 我尝试在 if 语句中删除此 dynamic_cast 条件并保留地图内容绘制(因此绘制了 2 倍以上的窗口,但是这数字,8,不是很大),但仍然很慢。
    • 我在发布答案后就看到了。您是否尝试过简单地注释掉 draw() 代码?
    • 如果我为地图内容注释掉 draw(),它工作得非常好。
    • 这似乎表明实际问题出在绘图调用中,而不是您存储它们的地图中,不是吗?
    猜你喜欢
    • 1970-01-01
    • 2012-08-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-02-23
    • 2011-12-20
    • 1970-01-01
    • 2022-01-13
    相关资源
    最近更新 更多