4

I have the following code -:

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

Output -:

abab
asas

abab
asas

The elements of the set are not being modified at all by the reverse() function.
I suspect that the elements inside a set cannot be modified at all. But, if this is the case, why doesn't the compiler give an error in the first place itself ?

I am using TDM-GCC 4.9.2 with -std=c++14 flag on Windows 7.

Anmol Singh Jaggi
  • 8,376
  • 4
  • 36
  • 77
  • 2
    You are operating on copies of the items, the originals in the `set` aren't changed. Use iterators to manipulate them directly. – πάντα ῥεῖ Jul 01 '15 at 06:19
  • Items in a set are sorted in a particular order. That is why inserting and removing is always relatively fast, no matter how big the set is. You can specify the order you want, but you cannot change it. If the order of the items matters to you use a sequential container such as a vector. – nwp Jul 01 '15 at 06:22
  • 1
    Possible duplicate of [C++ STL set update is tedious: I can't change an element in place](https://stackoverflow.com/questions/2217878/c-stl-set-update-is-tedious-i-cant-change-an-element-in-place) – underscore_d Sep 22 '18 at 12:43

3 Answers3

14

Elements of a std::set are const. If you want to mutate the elements you need to do insertions and removals to put the container in the state you want.

In your code example:

for (auto item : s)

gets translated into something like:

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

The loop induction variable item is a copy of the element from the set, not a reference to the actual element in the set. As a result, the set is not changed. To change a set you need to call a member function of set, e.g. insert or erase.

Changing item to &item won't help here; if you do this you'll get a compile-time error because the elements of the set are const, so you can't apply reverse to them.

Billy ONeal
  • 104,103
  • 58
  • 317
  • 552
5

This range based loop makes copies of every element in the set:

for ( auto item : s )

That is why you can modify item in the loop without triggering a compiler error.

If you wanted to modify the elements of a container, you'd need a reference. Using this would indeed result in a compiler error because the elements of a set can't be modified:

for ( auto& item : s )
{
  // s is a set. You cannot modify item
juanchopanza
  • 223,364
  • 34
  • 402
  • 480
1

Objects in an std::set are const, since they are used as keys. So you cannot modify objects in set like this .

mystic_coder
  • 462
  • 2
  • 10