views:

86

answers:

2

I'm learning C++ and can't get my head around this problem:

I have a simple class A

class A {
private:
    int ival;
    float fval;

public:
    A(int i = 0, float f = 0.0) : ival(i), fval(f) { }
    ~A(){ }
    void show() const { 
        cout << ival << " : " << fval << "\n";
    }
    void setVal(int i) {
        ival = i;
    }

    //const getters for both ival and fval

    //used for the default "lesser"
    friend bool operator<(const A& val1, const A& val2) {
        return val1.ival < val2.ival ? true : false;;
    }
}

Then I have a regular set<A> myset that gets filled with insert(A(2, 2.2)); in a loop.

Iterating to get all the values is not a problem but I want to modify the value within this iteration:

for(set<A>::iterator iter = set3.begin(); iter != set3.end(); iter++) {
    iter->setVal(1);
}

I assume that this should be doable, like you would do it in Java within a foreach loop. When compiling I get error: passing ‘const A’ as ‘this’ argument of ‘void A::setVal(int)’ discards qualifiers.

Looking at the sources of the STL set, i see that begin() is only available as a const method and I think this might be the problem. Messing around with const on the setVal() method got always the same error and wouldn't make much sense since I want to modify the value of A.

Is this the wrong approach of changing a bunch of A's values with a loop?

+4  A: 

The STL set does not let you change values it stores. It does that by returning a copy of the object through the iterator (not the actual one in the set).

The reason that set does this is because it's using < to order the set and it doesn't want to remake the entire tree every time you dereference the iterator, which it would have to do, since it doesn't know if you changed anything that changes the ordering.

If you need to update the set<>, remove the old value and add in a new one.

EDIT: just checked source to SGI STL and it says this:

 typedef typename _Rep_type::const_iterator iterator;

So, a set::iterator is just a set::const_iterator

Lou Franco
Does that mean I just had bad luck trying with a set and not with another container? Would this work with a vector or list or ...?
DrColossos
Yes, this works with a `std::vector`.
Pedro d'Aquino
Scharron
@DrColossos it will work with any non-ordered containers (list, vector, unordered_set, ...)
Scharron
I have worked with set<> implementations that actually made a copy, so that casting constness didn't help you. You have to assume that you can't get around this issue with a cast.
Lou Franco
If an implementation returned a copy of the key, then it would be non-compliant. Also note that you **cannot**, **must not** try to modify the object with a const-cast, as that can break the set invariants. This has been asked many times before in SO.
David Rodríguez - dribeas
+1  A: 
ereOn
No (at least I don't think so?). I use `set<A> myset;` and than add `A`'s like I described above.
DrColossos
Know this page myself, great ressource! Buf if the definition in the source is said to be const, where does the non-const `begin()` come from?
DrColossos
It's a mistake.iterator and const_iterator are the same type on ordered containers (thus having only one `begin() const` and `end() const` methods)
Scharron
ereOn