使用 SFML 的 C++ 中基于迭代器的循环和基于索引的循环之间存在显着的性能差异

Ahm*_*etK 1 c++ stdvector sfml c++17

我正在使用 C++ 中的 SFML 开发一个简单的 2D 网格可视化游戏引擎。我有一个带有 std::vector<sf::Vertex> 的 Grid 类,其中网格中的每个单元格由 6 个顶点表示。当我根据每个单元格的状态更新其颜色时,我观察到两个循环之间存在巨大的性能差异:一个循环使用向量的迭代器,另一个循环使用基于索引的方法。

这是差异所在:

inline void ChangeCellColor(Cell& cell, sf::Color color)
{
    // index-based loop
    auto index = cell.grid_y * width_ + cell.grid_x;
    for (int i = 0; i < 6; ++i)
    {
        vertices_[index * 6 + i].color = color;
    }

    // iterator-based loop (commented out for now)
    /*
    auto index = cell.grid_y * width_ + cell.grid_x;
    for (auto it = vertices_.begin() + index * 6; it != vertices_.begin() + index * 6 + 6; ++it)
    {
        it->color = color;
    }
    */
}
Run Code Online (Sandbox Code Playgroud)

使用基于索引的循环,我实现了 1150-1350 范围内的 FPS。然而,当我切换到基于迭代器的循环时,FPS 急剧下降到 30-45。

这两种方法之间如此巨大的性能差异背后的原因可能是什么?我是否遗漏了向量迭代器的一些内容?

环境:Visual Studio 2022,调试构建

pad*_*ddy 7

您很可能成为Checked Iterators的受害者。在调试版本中迭代标准容器时,这些因性能问题而臭名昭著。

可以使用宏_ITERATOR_DEBUG_LEVEL禁用它们。0您可以定义此宏以扩展到源中的值(在包含之前)vector(在包含 之前),或者在项目设置中执行此操作。

我个人会在项目设置中定义它(C / C++ > 预处理器 > 预处理器定义),但对于快速测试,您可以直接在源代码中执行此操作:

#define _ITERATOR_DEBUG_LEVEL 0
#include <vector>

// ...

inline void ChangeCellColor(Cell& cell, sf::Color color)
{
    auto index = cell.grid_y * width_ + cell.grid_x;
    for (auto it = vertices_.begin() + index * 6, end = it + 6; it != end; ++it)
    {
        it->color = color;
    }
}
Run Code Online (Sandbox Code Playgroud)

如果您使用的是带有预编译头的典型 Microsoft 项目stdafx.h,则可以将其放入其中。