Search code examples
c++c++17sfmlstdvector

Significant performance difference between iterator-based loop and index-based loop in C++ with SFML


I'm using SFML in C++ to develop a simple 2D grid visualization game engine. I have a Grid class with a std::vector<sf::Vertex> where each cell in the grid is represented by 6 vertices. When I update the color of each cell based on its state, I'm observing a massive performance difference between two loops: one using the iterator of the vector and the other using an index-based approach.

Here's where the difference appears:

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;
    }
    */
}

Using the index-based loop, I achieve FPS in the range of 1150-1350. However, when I switch to the iterator-based loop, the FPS drops dramatically to 30-45.

What could be the reason behind such a drastic performance difference between the two approaches? Am I missing something about vector iterators?

Env: Visual Studio 2022, Debug build


Solution

  • You are most likely falling victim to Checked Iterators. These are notorious for performance issues when iterating over standard containers in Debug builds.

    They can be disabled with the macro _ITERATOR_DEBUG_LEVEL. You can define this macro to expand to the value 0 in your source (before including vector), or do it in your project settings.

    I would personally define this in the project settings (C / C++ > Preprocessor > Preprocessor Definitions), but for a quickfire test you can do it directly in your source:

    #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;
        }
    }
    

    If you're using a typical Microsoft project with the precompiled header stdafx.h, you can put it in there.