justik
justik

Reputation: 4255

C++ , how to return a reference to the member variable from iterator

There is the following class B derived from std::vector

class B: public std::vector <unsigned int>
{
    public:
            B() : std::vector <unsigned int> ( 0 ) {}
};

and a class A witten as follows:

class A
{
    private:        
            B b;    
    double x;

public:
    B & getB () {return b;}
    B const & getB() const {return b;}

    bool operator() ( const A & a ) const
            {
                    return a < a.x;
            }
};

Why it is impossible to return a refererence to the variable b of some object A stored in std::list from its iterator (and how to do that)?

int main ()
{
std::set <A > alist;
std::set <A> ::iterator i_alist = alist.begin();

for (; i_alist != alist.end(); i_list++)
{
    B &il = (*i_alist).getB(); //Compiler error
    B &il2 = i_alist->getB(); //Compiler error

    il.push_back(10);   //Modify il and concurrently B
}
} 

Compiler error:

Error   1   error C2440: 'initializing' : cannot convert from 'const B' to 'B &'    d:\test.cpp

Thanks for your help...

Edit question:

The possible solution using const_cast :

B &il2 = const_cast <B&> ( i_alist->getB() );

Upvotes: 1

Views: 1286

Answers (2)

AnT stands with Russia
AnT stands with Russia

Reputation: 320421

This has very little to do with std::vector and everything to do with std::set. You store your objects in a std::set. Elements of std::set are not modifiable from the outside. Once you inserted an element into a set, you cannot change it.

For this reason, std::set::iterator might (and will) evaluate to a constant object, even if it is not a const_iterator (the language specification actually allows std::set::iterator and std::set::const_iterator to refer to the same type, but does not require it). I.e. in your example *i_list is a const-qualified object of type const A. The compiler will call the const version of getB, which returns const B &. You are apparently hoping to break through that constness, expecting the non-const version of getB to be called.

There's no way around it, unless you decide to use some sort of hack (const_cast etc.) to remove the constness from the set element and thus make the compiler to call non-const version of getB.

The const_cast-based hack-solution would look as

B &il = const_cast<A &>(*i_alist).getB();

or you can remove the constness later, from the returned B reference

B &il = const_cast<B &>((*i_alist).getB());
B &il2 = const_cast<B &>(i_alist->getB());

Upvotes: 7

Arne Mertz
Arne Mertz

Reputation: 24596

There are some things that look weird about your example:

  1. Never derive from std::vector. It's not designed for that use. And there normally is no reason to do so, except laziness, i.e. to avoid some typing.
  2. What is that A::operator() for? Looks like some strange way to provide a Comparator for the std::set you are using. Normally you don't alter a class just because you stuff it into a std::set somewhere. If you really want to be able to compare your A's (generally, not just for the set), then write a proper free bool operator<(A const&, A const&); If it's just for the set, write a custom Comparator in the place where you use the set. (That comparator should not need to access A's privates)
  3. What is the A::x used for? Only for comparison or even only for the comparison inside the set? If it's just that, consider to use a std::map<double, A> or even a std::map<double, B> where you put your x as the keys and the actual objects as the values.

You see, there are a lot of open questions I ask, and maybe the solution (using a map) does not even fit your problem. That is because you did not show us the real code you have but only some example with meaningless names. So we only see what you are trying to do, not what you actually want to achieve with your code.

PS: maybe you don't even need an ordered container in the first place, it could suffice to stuff all the objects into a std::vector and then std::sort it. Depends on the kind of objects you really have (the A's of your example are cheap to copy/swap) and of the ways you use the container - how the insertions are interleaved with the loops and so on.

Upvotes: 0

Related Questions