1

In the following program, I have a class A with a non-static function void add(). I want use the iterator to call add() for each element in the set, but there is a error at the last element.

How can I fix it?

#include <iostream>
#include <set>

using namespace std;

class A
{
private:
    int a;
public:
    A(int x) { a = x; }
    void add() {a = a + 1; }
    bool operator<(A x) const { return a < x.a; }
};

int main()
{
    //type of the collection
    typedef set<A> IntSet;

    //define a IntSet type collection
    IntSet col1;
    IntSet::iterator pos;

    //insert some elements in arbitrary order
    col1.insert(A(3));
    col1.insert(A(4));
    col1.insert(A(5));

    //iterator over the collection and print all elements

    for(pos = col1.begin(); pos != col1.end(); ++pos)
    {
        (*pos).add();
        // ERROR!: Member function 'add' not viable:
        // 'this' argument has type'const value_type' 
        // (aka 'const A'), but function is not marked const
    }
    cout << endl;
}
intcreator
  • 4,206
  • 4
  • 21
  • 39
iLeoDo
  • 397
  • 3
  • 11
  • In a `std::set` you are **not allowed** to change the contents (it would mess up the ordering). `*pos` is giving you a `const A`, hence you can't call the non-`const` function `add()` on it. If you want to be able to change the stored `A`s you need to use a different container. – BoBTFish Apr 12 '13 at 16:15
  • You cannot modify set<> and thus all set iterators are constant. http://stackoverflow.com/questions/5632079/why-does-stdset-insert-return-a-non-const-iterator-and-yet-i-cannot-modify – alexrider Apr 12 '13 at 16:17
  • 1
    `col1.insert(*new A(5));` causes a memory leak, the syntax you were looking for is `col1.insert(A(5));`, i.e. "calling" the classname to create an instance of it. – Ulrich Eckhardt Apr 12 '13 at 17:29

1 Answers1

4

Items contained in a set<> container are considered const and cannot be modified. If they did, their identity might change but set<> wouldn't be aware of this, wreaking havoc on its internal structure as an item would be stored in a bucket where it didn't belong!

Consider, for example, that set<> uses your custom operator< overload in order to sort its contents. What would you expect to happen if you change the a member variable while the object is contained in a set? The set won't know that a changed and will leave the object where it was.

To fix this potential problem, set<> only gives you references to const instances of contained objects.

You will only be able to use const members of your class in this context, and add() is not declared const. If you want to modify the object and have those changes reflected in the set, you will have to make a copy of the object, remove the original object from the set, make the change to your copy, and then add the copy to the set.

cdhowie
  • 158,093
  • 24
  • 286
  • 300