Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

std::multiset::iterator = NULL no longer valid?

Tags:

c++

c++11

I have some code that I'm updating to C++11 using gcc 4.7 (from 3.1)

I have a multiset defined as a private member of a class:

multiset <Object*, objectcomp> objects_;

In the code is a segment that looks like this (p_q is a pair of multiset iterators, sorry about that nasty line, can't wait to replace that with auto, haha):

void Terrain::removeObject(Object* obj){
    pair<multiset<Object*, objectcomp>::iterator, multiset<Object*, objectcomp>::iterator> p_q;
    multiset<Object*, objectcomp>::iterator p,q;
    q = NULL;
    p_q = objects_.equal_range(obj);
    for(p = p_q.first; p != p_q.second; p++){
        if(*p == obj) {q=p; break;}
    }
    if(q!=NULL){
        ... do stuff based on q no longer being null
    }
}

This won't compile anymore. Can you not set iterators to null anymore? What is the alternative? (nullptr doesn't work either)

like image 464
Eric B Avatar asked Nov 29 '12 01:11

Eric B


2 Answers

It was never legal to set iterators to NULL. You may have gotten lucky because your particular implementation happened to use pointers as iterators for that type, but it was still illegal.

The right answer is:

q = objects_.end();

Or, in some cases:

q = multiset<Object*, objectcomp>::iterator();
like image 178
abarnert Avatar answered Sep 22 '22 01:09

abarnert


You never could set an iterator to NULL. If the above code ever worked, it was by sheer accident. Given any reasonable implementation of multiset, it's hard to see how it could ever have compiled, let alone run.

The best way to get a "nowhere" iterator is to use the end of the container. Replace q = NULL with q = objects_.end().

Also, never put raw pointers in a container; it's an open invitation to memory leaks. You almost certainly want either multiset<Object,comp> or multiset<shared_ptr<Object>,comp>.

like image 38
Ross Smith Avatar answered Sep 18 '22 01:09

Ross Smith