1

I have the following code:

    std::set< std::vector<int> > testSet;
    vector<int> v0 = vector<int>(3);
    vector<int> v11 = vector<int>(3);
    v0[0] = 0;
    v0[1] = 10;
    v0[2] = 20;
    std::cout << v0[0] << endl;
    testSet.insert(v0);
    v0[0] = 1;
    v0[1] = 11;
    v0[2] = 22;
    testSet.insert(v0);
    std::set< std::vector<int> >::iterator it;

    for (it = testSet.begin(); it != testSet.end(); it++) {
        const std::vector<int>& i = (*it); 
        std::cout << i[0] << endl;  
    }

When I change:

const std::vector<int>& i = (*it)

to:

std::vector<int>& i = (*it)

it stops working. Apparently (*it) returns a const vector<int>&, but why is it the case? The set contains vectors, not const vectors.

Piotr Skotnicki
  • 46,953
  • 7
  • 118
  • 160
user107986
  • 1,461
  • 1
  • 17
  • 24
  • 9
    because any change to vector would break the ordering within set – Piotr Skotnicki Sep 19 '14 at 10:29
  • Is there any information about this on cppreference? http://www.cplusplus.com/reference/set/set/ I don't see it. – user107986 Sep 19 '14 at 10:35
  • 2
    First mention is in the second paragraph: `The value of the elements in a set cannot be modified once in the container (the elements are always const)` Then after the member types: `*Note: All iterators in a set point to const elements.` The reason, why it must be so is not elaborated on the site. – eerorika Sep 19 '14 at 10:35
  • 1
    Is there any reason why people answer with comments instead of with *answers*? – Fytch Sep 19 '14 at 11:03
  • @user107986 the cppreference link would be http://en.cppreference.com/w/cpp/container/set -- you linked to cplusplus.com – Cubbi Sep 19 '14 at 12:57

2 Answers2

3

This is because your actual testSet declaration looks as follows:

std::set<std::vector<int>, std::less<std::vector<int>>> testSet;
//                         ~~~~~~~~~~~~~~~~~~~~~~~~~~^

That is, the value_type itself is used as the argument for ordering predicate (no matter if it is std::less<T> or a custom one), and its location within std::set data structure (possibly RB-tree) depends on its original value (at the time of insert operation). Thus, changing the content without reordering the std::set would break the ordering logic.

The constness of non-const iterator is also mentioned in the standard:

§ 23.2.4 Associative containers [associative.reqmts]

  1. iterator of an associative container is of the bidirectional iterator category. For associative containers where the value type is the same as the key type, both iterator and const_iterator are constant iterators. It is unspecified whether or not iterator and const_iterator are the same type.
Community
  • 1
  • 1
Piotr Skotnicki
  • 46,953
  • 7
  • 118
  • 160
1

I am providing a contradictory answer. The standard is overly presumptuous in saying that changing the object will change the order. I can easily have an object that itself has constant data that can be used for ordering AND non-constant data that doesn't have anything to do with its order within the set. My objects have a const std::string m_name that is used by my custom comparator for ordering, but has a whole slew of setters for changing other things about it.

Box Box Box Box
  • 5,094
  • 10
  • 49
  • 67