Westu
Westu

Reputation: 11

Why can't I use the member function to get a member variable when I use <set> iterator?

class Test
{
private:
    int v;

public:
    Test(int h)
    {
        v = h;
    }
    int getV()
    {
        return v;
    }
    bool operator < (const Test& b) const
    {
        return v < b.v;
    }
};

int main()
{
    set <Test> st;
    for(int i = 1; i <= 10; i++)
    {
        Test t(i);
        st.insert(t);
    }

    for(set<Test>::iterator it = st.begin(); it != st.end(); it++)
    {
        cout << (*it).getV() << endl;
        //Test it2 = *it;
        //cout << it2.getV() << endl;
    }

    return 0;
}

It will be

|error: passing 'const Test' as 'this' argument of 'int Test::getV()' discards qualifiers [-fpermissive]|

but if I use Test it2 = *it; cout << it2.getV() << endl;, it will work well. Why does it use the words 'const Test' and why the code can't work?

Upvotes: 0

Views: 67

Answers (3)

Nipun Talukdar
Nipun Talukdar

Reputation: 5387

Another way is to remove the constness of the object refereed by the iterator. In that case, getV doesn't need to be a const method. Check the modified code below:

for(set<Test>::iterator it = st.begin(); it != st.end(); it++)
{
    cout << (const_cast<Test*>(&(*it)))->getV() << endl;
    //Test it2 = *it;
    //cout << it2.getV() << endl;
}

I don't understand why the above answer was down-voted. I just gave an example of doing it another way. In some cases we have to do that. There are times when we need to set some value in the object. Can the down-voters kindly see the reasons looking at the below example:

#include <iostream>
#include <set>
using namespace std;

class Test
{
private:
    int v;
    int w;

public:
    Test(int h, int i)
    {
        v = h;
        w = i;
    }
    int getV() const
    {
        return v;
    }
    int getW() const
    {
        return w;
    }

    void setW(int a) // This will not screw up the set as only v is used for comparison
    {
        w = a;
    }

    // Operator < is not using only v for comparison
    // of objects and not using w for that purpose
    bool operator < (const Test& b) const
    {
        return v < b.v;
    }
};

int main()
{
    set <Test> st;
    for(int i = 10; i >= 0; i--)
    {
        Test t(i, i);
        st.insert(t);
    }

    for(set<Test>::iterator it = st.begin(); it != st.end(); it++)
    {
        const_cast<Test*>(&(*it))->setW(1000);
    }


    for(set<Test>::iterator it = st.begin(); it != st.end(); it++)
    {
        cout << it->getV() << " " << it->getW() << endl;
    }
    return 0;
}

Upvotes: -3

Michael Burr
Michael Burr

Reputation: 340228

A set iterator is a const iterator. You'll need to mark getV() as const (which it should be anyway since it doesn't change the object):

int getV() const // <--
{
    return v;
}

Upvotes: 1

bames53
bames53

Reputation: 88185

std::set iterators return const references because sets are sorted, and if you change the value of an object in a set then it could be in the wrong position for the new value. That could make the object un-findable and worse.

When you do

Test it2 = *it;

You're making a copy of the object, and you can modify the copy as much as you like. You can't mess up the set by modifying the copy.

The problem is that your getV() method is not correctly const qualified. It should be:

int getV() const
{
    return v;
}

And then the first code will compile and work just fine.

Failing to apply const where it's correct will often cause these kinds of problems. You should work to correctly apply const-qualificiations.

Upvotes: 6

Related Questions