Изменение элементов в std:: set


У меня есть следующий код -:

int main()
{
    set<string> s;
    s.insert( "asas" );
    s.insert( "abab" );

    for ( auto item : s )
    {
        cout << item << "n";
        reverse( item.begin(), item.end() );
    }

    cout << "n";

    for ( auto item : s )
    {
        cout << item << "n";
    }
}

Вывод -:

abab
asas

abab
asas

Элементы множества вообще не модифицируются функцией reverse().
Я подозреваю, что элементы внутри набора вообще не могут быть изменены. Но если это так, то почему компилятор не выдает ошибку в первую очередь сам ?

Я использую TDM-GCC 4.9.2 с флагом -std=c++14 в Windows 7.

3 2

3 ответа:

Элементами a std::set являются const. Если вы хотите изменить элементы, вам нужно выполнить вставки и удаления, чтобы поместить контейнер в нужное состояние.

В примере кода:

for (auto item : s)

Переводится примерно так:

for (auto iter = s.begin(); iter != s.end(); ++iter)
{
    auto item = *iter; // Copy!
    // loop body
}

Переменная индукции цикла item являетсякопией элемента из set, а не ссылкой на фактический элемент в set. В результате set не изменяется. Чтобы изменить набор, необходимо вызвать функцию-член из set, например insert или erase.

Изменение item на &item здесь не поможет; если вы сделаете это, вы получите ошибку компиляции, потому что элементы набора являются const, поэтому вы не можете применить reverse к ним.

Этот цикл на основе диапазона создает копии каждого элемента в наборе:

for ( auto item : s )
Именно поэтому вы можете изменять item в цикле, не вызывая ошибки компилятора.

Если вы хотите изменить элементы контейнера, вам понадобится ссылка. Использование этого действительно приведет к ошибке компилятора, потому что элементы набора не могут быть изменены:

for ( auto& item : s )
{
  // s is a set. You cannot modify item

Объекты в наборе std:: являются const, так как они используются в качестве ключей. Таким образом, вы не можете изменять объекты в наборе, как это .