Is for(auto i : unordered_map) guaranteed to have the same order every time?

32,352

Solution 1

The iteration order of unordered associative containers can only change when rehashing as a result of a mutating operation (as described in C++11 23.2.5/8). You are not modifying the container between iterations, so the order will not change.

Although the specification doesn't explicitly state that rehashing can't occur at any other time, doing so would invalidate all iterators over the container, making any iteration at all impossible.

Solution 2

Why not build them together?

for(auto i : map)
{
    if(first) first = false;
    else{
        keys += ", ";
        query += ", ";
    }
    keys += i.first;

    values += i.second;
}

std::string query = "INSERT INTO table (" + keys + ") VALUES (" + values ")";

Looks nicer too imo.

Please note, if this section is performance critical, you could consider optimizing the string building process with std::stringstream as shown here, though it is not clear how much that might help

Share:
32,352
danijar
Author by

danijar

Researcher aiming to build intelligent machines based on concepts of the human brain. Website · Twitter · Scholar · Github

Updated on August 19, 2020

Comments

  • danijar
    danijar over 3 years

    When I iterate over a std::unordered_map with the range based for loop twice, is the order guaranteed to be equal?

    std::unordered_map<std::string, std::string> map;
    
    std::string query = "INSERT INTO table (";
    bool first = true;
    for(auto i : map)
    {
        if(first) first = false;
        else query += ", ";
        query += i.first;
    }
    query += ") ";
    
    query += "VALUES (";
    first = true;
    for(auto i : map)
    {
        if(first) first = false;
        else query += ", ";
        query += i.second;
    }
    query += ");"
    

    In the example above, the resulting string should be in that form. Therefore, it is important that both times, the order of iteration is the same.

    INSERT INTO table (key1, key2, key3) VALUES (value1, value2, value3);
    

    Is this guaranteed in C++?

  • michelson
    michelson over 10 years
    Consider using ostringstream instead, but this is the better approach.
  • Karthik T
    Karthik T over 10 years
    @D.Shawley yes probably if this is a performance intensive section. Else this might be better purely on readability grounds, either way I was mainly focusing on the fix to his problem.
  • danijar
    danijar over 10 years
    Great! I could even cut that down, because the first key and value is given. std::string keys = "id", values = to_string(Id); for(auto i : serialized) keys += ", " + i.first, values += ", " + i.second;.