How to check if the iterator is initialized? - c++

If I use a default constructor for an iterator, how to check if it was assigned later on?
For pointers, I could do this :
int *p = NULL;
/// some code
if ( NULL == p ) {
// do stuff
}
How do I do the above for iterators?
Is it possible at all?
#include <iostream>
#include <list>
int main ()
{
std::list<int>::iterator it;
if ( NULL == it ) // this fails
{
std::cout<<"do stuff" << std::endl;
}
}

I managed to find this in the current standard (c++03 ). 24.1 p 5 tells :
Just as a regular pointer to an array guarantees that there is a
pointer value pointing past the last element of the array, so for any
iterator type there is an iterator value that points past the last
element of a corresponding container. These values are called
past-the-end values. Values of an iterator i for which the expression
*i is defined are called dereferenceable. The library never assumes
that past-the-end values are dereferenceable. Iterators can also have
singular values that are not associated with any container. [Example:
After the declaration of an uninitialized pointer x (as with int* x;),
x must always be assumed to have a singular value of a pointer. ]
Results of most expressions are undefined for singular values; the
only exception is an assignment of a non-singular value to an iterator
that holds a singular value. In this case the singular value is
overwritten the same way as any other value. Dereferenceable values
are always non- singular.
(Emphasis mine)
So the answer is : no, it is not possible.

Most iterators don't have any global special values in the same way that all pointers can be NULL. Typically, though, you'll be working with specific containers, and if you keep one iterator per container, then you can use end() as the sentinel value:
std::list<int> mylist;
std::list<int>::iterator it = mylist.end();
/* do stuff */
if (it == mylist.end()) { ... }
I'm not sure if insertion/deletion invalidates the end() iterator, though, so if you're planning on modifying your container, maybe save a copy of the original end, too:
std::list<int>::iterator end = mylist.end(), it = end;
if (it == end) { ... }
Though again I'm actually not sure if it's well-defined to compare two invalid iterators (in the event that the two do get invalidated).

This question has already been treated in Stackoverflow. The quintessence is that the default constructor initializes an iterator to a singular value, and the only addmissible operation on it is to assign it another iterator value. In particular it is not possible to query the value of such unitialized iterator. Therefore it is a good programming practice to initialize the iterator to a specific value of a specific container, which then can be tested for.

Since there is no default value for iterators (like there is NULL for pointers), in situation where i need a common default value for a Object::iterator (before any actual Object has been created) I create a dummy static variable and use its ::end() as the default.
Update : This only works for Release, because in DEBUG (or with _HAS_ITERATOR_DEBUGGING=1) comparison operators check if both iterators point to the same object/container.
For example for vector<int> I would do :
class A
{
public :
A() : myIterator1(dummyVector.end()), myIterator2(dummyVector.end()) {}
// needed iterators
vector<int>::iterator myIterator1;
vector<int>::iterator myIterator2;
static const vector<int> dummyVector;
}
#define IT_NULL A::dummyObject.end()
void maint() {
A::dummyObject = vector<int>(); // initialize the Null iterator
A a;
if(a.myIterator1 == IT_NULL) cout << "Iterator not yet initialized";
}

You can't. ll you can do is compare against list end
it != mylist.end();

In C++, uninitialized local variables can have any value i.e it contains simply garbage. That implies, you cannot check it against some well-defined value, to determine if the variable is uninitialized or not.
Not only that if the variable is not initialized and you write this:
if ( NULL == it ) // this fails
then it invokes undefined behavior.

Maybe you should always assign a predefined value, like NULL, after creating the iterator. Later you can easily check against NULL.
This will make your code more portable, as you will not depend on what starting values the uninitialized variables take at the beginning.

if(std::list<int>::iterator() == it)
But I suspect... may it's possible, that a valid iterator could pass the comparison.
Better to avoid these situations. If it's impossible store the iterator by a pointer.
std::auto_ptr<std::list<int>::iterator> it;

The best way to do this I can think of is something like
#include <utility>
#include <map>
#include <typeinfo>
#include <string>
namespace nulliterators {
typedef std::map<std::string, void*> nullcntT;
nullcntT nullcontainers;
template<class containerT>
typename containerT::iterator iterator() {
containerT* newcnt = new containerT();
std::string cnttypename = typeid(*newcnt).name();
nullcntT::iterator i = nullcontainers.find(cnttypename);
if (i==nullcontainers.end()) {
nullcontainers.insert(make_pair(cnttypename, newcnt));
return newcnt->end();
}else{
delete newcnt;
return (static_cast<containerT*>(i->second))->end();
}
}
}
template<class containerT>
typename containerT::iterator nulliterator() { return nulliterators::iterator<containerT>(); }
#include <list>
#include <iostream>
int main(){
std::list<int>::iterator nullinitized = nulliterator< std::list<int> >();
std::list<int> somelist;
std::list<int>::iterator initialized = somelist.end();
if (nullinitized == nulliterator< std::list<int> >())
std::cout << "nullinitized == nulliterator< std::list<int> >()\n"; //true
else
std::cout << "nullinitized != nulliterator< std::list<int> >()\n";
if (initialized == nulliterator< std::list<int> >())
std::cout << "initialized == nulliterator< std::list<int> >()\n";
else
std::cout << "initialized != nulliterator< std::list<int> >()\n"; //true
return 0;
}
but it's not exactly a safe solution (because it relies on the non-const global containers in nullcontainers).

As far as I know you must always initialize your iterators and the easiest way is to make them equal to 'container'.end()
In certain cases it looks like working, we had some problems with code that worked with VC6 and stopped working with VC2010. Look at this example compiled with g++ where it works for the vector but not for the map:
# Test iterator init, compile with: g++ test-iterator.cpp -o test-iterator
#include <iostream>
#include <vector>
#include <map>
int main()
{
std::vector<int> vec;
std::vector<int>::iterator it;
if (it != vec.end())
{
std::cout << "vector inside!" << std::endl;
}
else
{
std::cout << "vector outside!" << std::endl;
}
std::map<int, int> mp;
std::map<int, int>::iterator itMap;
if (itMap != mp.end())
{
std::cout << "map inside!" << std::endl;
}
else
{
std::cout << "map outside!" << std::endl;
}
return 0;
}

I used the following solution:
const MyList_t::const_iterator NullIterator(NULL);
const_iterator MyList_t::MyIterator;
Then a check is possible:
if (NullIterator != MyIterator) {}

Related

A list iterator reference - Program output

Given the following algorithm:
#include <iostream>
#include <list>
int main ()
{
std::list<int> mylist = {5,10,15,20};
std::cout << "mylist contains:"<<"\n";
//for (auto it = mylist.begin(); it != mylist.end(); ++it)
auto it = mylist.begin();
while ( it != mylist.end())
{
std::cout << *it;
std::cout << " "<< &it<<std::endl;
it++;
}
std::cout << '\n';
return 0;
}
The output of this program is:
mylist contains:
5 0x7dc9445e5b50
10 0x7dc9445e5b50
15 0x7dc9445e5b50
20 0x7dc9445e5b50
Since we are moving our iterator, why the address doesn't change?
I was excepting a 4 bytes offset of the reference.
Try this instead:
std::cout << " "<< &*it<<std::endl;
Read this for a description of legacy bidirectional iterators.
https://en.cppreference.com/w/cpp/named_req/BidirectionalIterator
It's not incredibly obvious from this documentation but for this iterator and for iterators in general throughout STL the operator *() will return either:
T & operator *();
or
const T & operator *() const; // for const iterators (list iterator in this case).
I hope this is a bit more explanatory than my previous rather terse answer.
Your problem is pretty simple: it is a variable. Right now, you're printing out the address of that variable. You assign different values to that variable, but the variable is stored at the same location in memory for the entirety of its existence, so when you print out its address, you see the same value every time.
What you want to do is print out the value stored in that variable--the address of the object to which the iterator refers. In the case of an iterator, it can be somewhat tricky to do that, because an iterator is an abstraction--by design, you don't really know what it contains.
We can, however, take a fairly solid guess about how an iterator for an std::list is probably implemented. In particular, it's probably something like this:
template <class T>
class iterator {
T *data;
public:
T &operator*() { return *data; }
// ... and many more functions we don't care about for now
};
The important point here is that although it may store different data to produce its result, operator* needs to return a reference to the object to which the iterator refers. So, to get the address that's (at least effectively) stored in the iterator, we can use operator* to get a reference to the object, then & to take the address of that object.
The downside: while this tells you the addresses of the objects the iterator refers to at different times, it doesn't necessarily tell you what the iterator itself really contains. As long as the iterator produces the correct results from the specified operations, the iterator is free to produce them in essentially any way it sees fit (but that said, with an iterator for an std::list, yes, it's probably going to use a pointer).

For Random Access Iterator (vector iterator), are the iterators C++ style pointers?

I have the following code to randomize the elements in a list container:
#include <vector>
#include <list>
#include <iterator>
#include <algorithm>
#include <iostream>
using namespace std;
template<class RandomAccesIterator>
void randomize(RandomAccesIterator iterBegin, RandomAccesIterator iterEnd)
{
while (iterBegin != iterEnd)
{
iter_swap(iterBegin, iterBegin + rand() % (iterEnd - iterBegin));
++iterBegin;
}
}
And then later in main():
int main()
{
//container used as to apply algorithm to.
list<int> List = {34,77,16,2,35,76,18,2};
//randomize example.
cout << "calling randomize on sorted vector: " << endl;
List.sort();
vector<int> temp(List.begin(), List.end());
cout << "before randomize: " << endl;
for (vector<int>::iterator it = temp.begin(); it != temp.end(); it++)
{
cout << *it << " ";
}
cout << endl;
randomize(temp.begin(),temp.end());
cout << "after randomize: " << endl;
for (vector<int>::iterator it = temp.begin(); it != temp.end(); it++)
{
cout << *it << " ";
}
cout << endl<<endl;
return 0;
}
I had a couple of questions:
I believe performing iterEnd - iterBegin (as shown in the template function) is a valid operation, because both iterEnd and iterBegin are C++ style pointers. and subtracting these pointers gives the distance between them. Am I correct?
I tried the following in the immediate window:
iterEnd
{-33686019}
[ptr]: 0x00ba4f78 {-33686019}
[Raw View]: {...}
it means iterEnd is a pointer, whose value is 0x00ba4f78, and it points to the garbage value of -33686019. I believe I am correct here?
So, the iterator is a pointer, for random access iterators. Is it true for all iterator types (Input/output iterators, Forward iterators, BiDirectional iterators)? If those iterators are not C++ style pointers, then what are those?
I also tried the following in the immediate window:
&iterEnd
0x006ff368 {-33686019}
[ptr]: 0x00ba4f78 {-33686019}
[Raw View]: 0x006ff368 {...}
&&iterEnd
expected an expression
Why is &iterEnd giving me an address? It should give me the message "expected an expression", as, &&iterEnd does.
How are random access iterators implemented? - I am asking because iterEnd gives me a pointer value and, &iterEnd also gives me a (different) pointer value. Is the random access iterator a pointer within a pointer?
For Random Access Iterator (vector iterator), are the iterators C++
style pointers?
Short answer -- it depends on the compiler.
The internals of a vector iterator is implementation-defined. The std::vector<T>::iterator could have operator - overloaded, thus it gives the illusion of pointer subtraction. Thus if you assume that vector iterators are simple pointers, writing code assuming they are simple pointers will break using various compilers, while for other compilers it will compile successfully.
One such famous case is Visual C++, where in version 6.0, vector iterators were simple pointers, thus many authors at that time using that compiler would write code with the assumption that a std::vector<T>::iterator was just a T*. The code compiled successfully and worked correctly due to the fact that vector iterators were implemented as pointers.
An example would be something like this:
#include <vector>
void foo(char *c)
{
}
int main()
{
std::vector<char> vc;
foo(vc.begin());
}
No compile errors, since vc.begin() was a simple char *.
Then came the subsequent versions of Visual C++, and that code that used to compile successfully under 6.0 is now broken. The std::vector<T>::iterator was no longer a simple T*, but a struct. A lot of code based on the (faulty) reasoning of an iterator being a simple pointer had to be changed for Visual C++ > version 6.0.

Incrementing iterator that is used as first and last of std::multimap erase range

While running an example that shows how to erase a range from std::map/multimap I have noticed strange behaviour in the following code:
#include <map>
#include <iostream>
#include <string>
int main()
{
std::multimap<int, std::string> myMap;
myMap.insert(std::make_pair(3, "three1"));
myMap.insert(std::make_pair(3, "three2"));
myMap.insert(std::make_pair(3, "three3"));
myMap.insert(std::make_pair(45, "fourty five"));
myMap.insert(std::make_pair(-1, "minus one"));
std::multimap<int, std::string>::iterator iter = myMap.find(3);
if (iter != myMap.end()) {
myMap.erase(iter, iter++); //segmentation fault(!)
}
for (auto element : myMap) {
std::cout << element.first << " -> " << element.second << std::endl;
}
return 0;
}
Which I build with command g++ --std=c++11 main.cpp (I use g++ 5.2.1).
Why post-incrementation of my iterator causes a Segmentation fault?
I would rather say that this should create 2 copies of this iterator, pass them into the erase method, "erase nothing" just as would code myMap.erase(iter, iter); and then increment the iter.
What logic stands behind this segfault?
Is this an invalid use of iter iterator? If so - why?
BTW.
It compiles when I use pre-incrementation myMap.erase(iter, ++iter) and here it "erase nothing" as I mentioned above.
The order of evaluation of the arguments to a function call is not defined. So when you write:
myMap.erase(iter, iter++); //segmentation fault(!)
the compiler is free to evaluate the second argument first, or not. As you use the same iterator, but have a side effect, you get Undefined Behaviour (refer to C++ standard, section 1.9/15).
For example, if the compiler evaluates first the second argument iter++, the incremented iterator would be used as the first argument, while second argument is not incremented iter. As a consequence: the range passed to erase() would be [std::next(iter), iter)- the function might attempt to erase elements that are out of range (i.e. UB).
As suggested by David in the comments, you can solve the issue with iter = myMap.erase(iter) (or using a range without side effects).

Why adding to vector does not work while using iterator?

I have two code sample, which do exactly same thing. One is in C++03 and C++11.
C++ 11
int main()
{
vector<int> v = {1,2,3};
int count = 0;
for each (auto it in v)
{
cout << it<<endl;
if (count == 0)
{
count++;
v.push_back(4);//adding value to vector
}
}
return 0;
}
C++ 03
int main()
{
vector<int> v = {1,2,3};
int count = 0;
for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
{
cout << *it<<endl;
if (count == 0)
{
count++;
v.push_back(4);//adding value to vector
}
}
return 0;
}
Both the codes are giving following exception.
Now when I see vector::end() implementation,
iterator end() _NOEXCEPT
{
// return iterator for end of mutable sequence
return (iterator(this->_Mylast, this));
}
Here, inline function clearly takes _Mylast to calculate end. So, when I add, it pointer will be incremented to next location, like _Mylast++. Why I am getting this exception?
Thanks.
A vector stores its elements in contiguous memory. If that memory block needs to be reallocated, iterators become invalid.
If you need to modify the vector's size while iterating, iterate by index instead of iterator.
Another option is to use a different container with a different iterator behavior, for example a list will allow you to continue iterating as you insert items.
And finally, (dare I suggest this?) if you know the maximum size your vector will grow to, .reserve() it before iterating over it. This will ensure it doesn't get reallocated during your loop. I am not sure if this behavior is guaranteed by the standard though (maybe someone can chime in); I would definitely not do it, considering iterating by index is perfectly safe.
Your push_back is invalidating the iterator you're using in the for loop, because the vector is reallocating its memory, which invalidates all iterators to elements of the vector.
The idiomatic solution for this is to use an insert_iterator, like the one you get from calling std::back_insterter on the vector. Then you can do:
#include <iostream>
#include <iterator>
#include <vector>
int main()
{
std::vector<int> v;
auto inserter = std::back_inserter(v);
for(int i=0; i<100; ++i)
inserter = i;
for(const auto item : v)
std::cout << item << '\n';
}
And it will ensure its own validity even through reallocation calls of the underlying container.
Live demo here.

How to tell std::set to 'refresh' its ordering?

If the value of an element in a set changes the ordering may be no longer correct. As illustrated in this little program:
#include <algorithm>
#include <iostream>
#include <set>
#include <string>
struct Comp
{
bool operator()(const std::string * lhs, const std::string * rhs)
{
return *lhs < *rhs;
}
};
int main()
{
typedef std::set<std::string*, Comp> MySet;
MySet mySet;
std::string * a = new std::string("a");
mySet.insert(a);
std::string * c = new std::string("c");
mySet.insert(c);
std::string * b = new std::string("b");
mySet.insert(b);
for (MySet::iterator it = mySet.begin(); it != mySet.end(); ++it)
{
std::cout << *(*it) << std::endl;
}
// Ouput has correct order:
// a
// b
// c
*b = "z";
std::cout << std::endl;
std::string * d = new std::string("d");
mySet.insert(d);
for (MySet::iterator it = mySet.begin(); it != mySet.end(); ++it)
{
std::cout << *(*it) << std::endl;
}
// Output no longer ordered correctly:
// a
// d
// z
// c
return 0;
}
How can I tell the set to 'refresh' its internal sorting?
Very similar subject here (though not quite a duplicate, because you're storing pointers to mutable objects with a custom comparison):
what happens when you modify an element of an std::set?
Basically, don't do what you're trying to do. Instead, when you want to modify an object that a set holds a pointer to, remove the pointer first, then modify the object, then re-insert the pointer.
Simply, you can't. If you place an item into a set, you should not change the item in a way that changes its ordering. If you need to change an item in this way then you need to remove it from the set (set::erase), and reinsert a new item (std::insert) with the new value.
If the value of an element in a set changes
Stop! This cannot legally occur.
std::set does not provide any means to do what you're asking, because it's already a pre-requisite that a manual re-order shall never be required.
It's worth point out that if you're using vs 2008, the std::set implementation supports non-const iterators, making the code you describe compile successfully using that library. In other stl implementations (for instance sgi's), set::const_iterator and set::iterator are of the same type which would complain about explicitly setting a new key value.
Copy it into itself using a different comparison predicate.
std::set MySet();
/* add entries*/
MySet = std::set(MySet.begin(), MySet.end(), Comp);
Usually this is used to specify a different comparison operation, eg to sort it using a different part of a stored class/struct.