what is the difference between const_iterator and iterator? [duplicate] - c++

This question already has answers here:
What is the difference between const_iterator and non-const iterator in the C++ STL?
(7 answers)
Closed 4 years ago.
What is difference between these two regarding implementation inside STL.
what is the difference regarding performance?
I guess when we are traversing the vector in "read only wise", we prefer const_iterator, right?
Thank you.

There is no performance difference.
A const_iterator is an iterator that points to const value (like a const T* pointer); dereferencing it returns a reference to a constant value (const T&) and prevents modification of the referenced value: it enforces const-correctness.
When you have a const reference to the container, you can only get a const_iterator.
Edited: I mentionned “The const_iterator returns constant pointers” which is not accurate, thanks to Brandon for pointing it out.
Edit: For COW objects, getting a non-const iterator (or dereferencing it) will probably trigger the copy. (Some obsolete and now disallowed implementations of std::string use COW.)

Performance wise there is no difference. The only purpose of having const_iterator over iterator is to manage the accessesibility of the container on which the respective iterator runs. You can understand it more clearly with an example:
std::vector<int> integers{ 3, 4, 56, 6, 778 };
If we were to read & write the members of a container we will use iterator:
for( std::vector<int>::iterator it = integers.begin() ; it != integers.end() ; ++it )
{*it = 4; std::cout << *it << std::endl; }
If we were to only read the members of the container integers you might wanna use const_iterator which doesn't allow to write or modify members of container.
for( std::vector<int>::const_iterator it = integers.begin() ; it != integers.end() ; ++it )
{ cout << *it << endl; }
NOTE: if you try to modify the content using *it in second case you will get an error because its read-only.

if you have a list a and then following statements
list<int>::iterator it; // declare an iterator
list<int>::const_iterator cit; // declare an const iterator
it=a.begin();
cit=a.begin();
you can change the contents of the element in the list using “it” but not “cit”,
that is you can use “cit” for reading the contents not for updating the elements.
*it=*it+1;//returns no error
*cit=*cit+1;//this will return error

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).

How does std::sort() get both iterators and pointers? [duplicate]

I have a custom vector container that internally stores item a linear array. Last night, I was trying to implement custom iterators for my class to be able to use them with STL algorithms. I have had some success that you can see in here:
Live example with custom iterators
While doing so, I discovered I can merely pass raw pointers to STL algorithm and they just seem to work fine. Here's the example without any iterators:
#include <cstddef>
#include <iostream>
#include <iterator>
#include <algorithm>
template<typename T>
class my_array{
T* data_;
std::size_t size_;
public:
my_array()
: data_(NULL), size_(0)
{}
my_array(std::size_t size)
: data_(new T[size]), size_(size)
{}
my_array(const my_array<T>& other){
size_ = other.size_;
data_ = new T[size_];
for (std::size_t i = 0; i<size_; i++)
data_[i] = other.data_[i];
}
my_array(const T* first, const T* last){
size_ = last - first;
data_ = new T[size_];
for (std::size_t i = 0; i<size_; i++)
data_[i] = first[i];
}
~my_array(){
delete [] data_;
}
const my_array<T>& operator=(const my_array<T>& other){
size_ = other.size_;
data_ = new T[size_];
for (std::size_t i = 0; i<size_; i++)
data_[i] = other.data_[i];
return other;
}
const T& operator[](std::size_t idx) const {return data_[idx];}
T& operator[](std::size_t& idx) {return data_[idx];}
std::size_t size(){return size_;}
T* begin(){return data_;}
T* end(){return data_+size_;}
};
template<typename T>
void print(T t) {
std::cout << t << std::endl;
}
int main(){
typedef float scalar_t;
scalar_t list [] = {1, 3, 5, 2, 4, 3, 5, 10, 10};
my_array<scalar_t> a(list, list+sizeof(list)/sizeof(scalar_t));
// works!
for (scalar_t* it = a.begin(), *end = a.end();
it != end; ++it)
std::cout << ' ' << *it;
std::cout << std::endl;
// works!
std::for_each(a.begin(), a.end(), print<scalar_t>);
std::cout << std::endl;
// works!
my_array<int> b(a.size());
std::copy(a.begin(), a.end(), b.begin());
// works!
scalar_t* end = std::remove(a.begin(), a.end(), 5);
std::for_each(a.begin(), end, print<scalar_t>);
std::cout << std::endl;
// works!
std::random_shuffle(a.begin(), end);
std::for_each(a.begin(), end, print<scalar_t>);
std::cout << std::endl;
// works!
std::cout << "Counts of 3 in array = " << std::count(a.begin(), end, 3) << std::endl << std::endl;
// works!
std::sort(a.begin(), end);
std::for_each(a.begin(), end, print<scalar_t>);
std::cout << std::endl;
// works!
if (!std::binary_search(a.begin(), a.end(), 5))
std::cout << "Removed!" << std::endl;
return 0;
}
Live example without iterators
My questions here are the following:
Does this always work for containers that have linear storage? I know that this would not work for linked-lists for example.
If they do work in this situation, why should I ever go through the hassle of implementing iterators anyway? I know how iterators generalize my code and whatnot, but if this simple array is all I ever need then I don't see the point.
What are the negative issues of what I'm doing if this approach would always work? For one thing, I can see I'm breaking data encapsulation.
One of the features of iterators being based on operator-overloading, is that pointers are already random-access iterators. This was a big design win in the early days of STL, as it made it easier to use algorithms with existing code (as well as making the interface more familiar to programmers). It's perfectly reasonable to wrap an array, add typedef T* iterator; typedef const T* const_iterator, return &array[0] from your begin() and &array[size] from your end(), and then use your container with any iterator-based algorithm. As you already realise, this will work for any container where elements are contiguous in memory (such as an array).
You might implement 'real' iterators if:
You have a different-shaped container (such as a tree or list);
You want to be able to resize the array without invalidating the iterators;
You want to add debugging checks to your iterator use, for example to check if the iterator is used after being invalidated or after the container has been deleted, or to bounds-check;
You want to introduce type-safety, and make sure people can't accidentally assign an arbitrary T* to a my_array::iterator.
I'd say this last advantage alone is well worth writing a trivial wrapper class for. If you don't take advantage of C++'s type system by making different kinds of thing have different types, you might as well switch to Javascript :-)
Yes. See Effective STL, Item 16, which demonstrates with linear storage containers you can simply take the address of an item and work with that pointer as if it pointed to a simple array.
I think you answered your own question – you probably shouldn't, if you know the simple array is all you'll ever need.
Probably the biggest issue is just that – breaking data encapsulation. Consider whether or not an abstraction such as an explicit iterator type would buy you anything versus the cost.
Does this always work for containers that have linear storage?
Yes, the iterator concepts were designed so that pointers could act as iterators over arrays.
If they do work in this situation, why should I ever go through the hassle of implementing iterators anyway?
There's no good reason to define your own iterator type in this situation, unless you want to do something like bounds-checking which can't be done with a simple pointer.
One slight benefit would be that you could include nested typedefs for the iterator's traits, as some of the standard iterator types do; but using pointers these are available from std::iterator_traits<T*> anyway.
What are the negative issues of what I'm doing if this approach would always work? For one thing, I can see I'm breaking data encapsulation.
To make the interface more consistent with STL-style containers, you should define iterator and const_iterator types (typedef aliases for the pointers), and provide const overloads of begin and end; and perhaps cbegin and cend for C++11 compatiblity.
There are various other requirements that you might want to conform to; see section 23.2 of the C++ standard for the gory details. But in general, it's more important to make iterators conform to their requirements, since STL-style algorithms work with iterators rather than containers, and by using pointers you already conform to those requirements.
It happens that pointers provide the interface required of random access iterators (dereference, increment, addition, difference, etc) and can be treated just like iterators.
It should always work for containers with contiguous storage.
You might wish to create your own iterators for the same reason you use methods instead of all public data in your classes: To encapsulate what's happening with an interface you can modify if you need to. As long as you typedef your T* to an iterator type this is probably not a significant issue. Additionally some algorithms may benefit from an iterator that's tagged with the iterator type, which you can't do for simple pointer types.

Can raw pointers be used instead of iterators with STL algorithms for containers with linear storage?

I have a custom vector container that internally stores item a linear array. Last night, I was trying to implement custom iterators for my class to be able to use them with STL algorithms. I have had some success that you can see in here:
Live example with custom iterators
While doing so, I discovered I can merely pass raw pointers to STL algorithm and they just seem to work fine. Here's the example without any iterators:
#include <cstddef>
#include <iostream>
#include <iterator>
#include <algorithm>
template<typename T>
class my_array{
T* data_;
std::size_t size_;
public:
my_array()
: data_(NULL), size_(0)
{}
my_array(std::size_t size)
: data_(new T[size]), size_(size)
{}
my_array(const my_array<T>& other){
size_ = other.size_;
data_ = new T[size_];
for (std::size_t i = 0; i<size_; i++)
data_[i] = other.data_[i];
}
my_array(const T* first, const T* last){
size_ = last - first;
data_ = new T[size_];
for (std::size_t i = 0; i<size_; i++)
data_[i] = first[i];
}
~my_array(){
delete [] data_;
}
const my_array<T>& operator=(const my_array<T>& other){
size_ = other.size_;
data_ = new T[size_];
for (std::size_t i = 0; i<size_; i++)
data_[i] = other.data_[i];
return other;
}
const T& operator[](std::size_t idx) const {return data_[idx];}
T& operator[](std::size_t& idx) {return data_[idx];}
std::size_t size(){return size_;}
T* begin(){return data_;}
T* end(){return data_+size_;}
};
template<typename T>
void print(T t) {
std::cout << t << std::endl;
}
int main(){
typedef float scalar_t;
scalar_t list [] = {1, 3, 5, 2, 4, 3, 5, 10, 10};
my_array<scalar_t> a(list, list+sizeof(list)/sizeof(scalar_t));
// works!
for (scalar_t* it = a.begin(), *end = a.end();
it != end; ++it)
std::cout << ' ' << *it;
std::cout << std::endl;
// works!
std::for_each(a.begin(), a.end(), print<scalar_t>);
std::cout << std::endl;
// works!
my_array<int> b(a.size());
std::copy(a.begin(), a.end(), b.begin());
// works!
scalar_t* end = std::remove(a.begin(), a.end(), 5);
std::for_each(a.begin(), end, print<scalar_t>);
std::cout << std::endl;
// works!
std::random_shuffle(a.begin(), end);
std::for_each(a.begin(), end, print<scalar_t>);
std::cout << std::endl;
// works!
std::cout << "Counts of 3 in array = " << std::count(a.begin(), end, 3) << std::endl << std::endl;
// works!
std::sort(a.begin(), end);
std::for_each(a.begin(), end, print<scalar_t>);
std::cout << std::endl;
// works!
if (!std::binary_search(a.begin(), a.end(), 5))
std::cout << "Removed!" << std::endl;
return 0;
}
Live example without iterators
My questions here are the following:
Does this always work for containers that have linear storage? I know that this would not work for linked-lists for example.
If they do work in this situation, why should I ever go through the hassle of implementing iterators anyway? I know how iterators generalize my code and whatnot, but if this simple array is all I ever need then I don't see the point.
What are the negative issues of what I'm doing if this approach would always work? For one thing, I can see I'm breaking data encapsulation.
One of the features of iterators being based on operator-overloading, is that pointers are already random-access iterators. This was a big design win in the early days of STL, as it made it easier to use algorithms with existing code (as well as making the interface more familiar to programmers). It's perfectly reasonable to wrap an array, add typedef T* iterator; typedef const T* const_iterator, return &array[0] from your begin() and &array[size] from your end(), and then use your container with any iterator-based algorithm. As you already realise, this will work for any container where elements are contiguous in memory (such as an array).
You might implement 'real' iterators if:
You have a different-shaped container (such as a tree or list);
You want to be able to resize the array without invalidating the iterators;
You want to add debugging checks to your iterator use, for example to check if the iterator is used after being invalidated or after the container has been deleted, or to bounds-check;
You want to introduce type-safety, and make sure people can't accidentally assign an arbitrary T* to a my_array::iterator.
I'd say this last advantage alone is well worth writing a trivial wrapper class for. If you don't take advantage of C++'s type system by making different kinds of thing have different types, you might as well switch to Javascript :-)
Yes. See Effective STL, Item 16, which demonstrates with linear storage containers you can simply take the address of an item and work with that pointer as if it pointed to a simple array.
I think you answered your own question – you probably shouldn't, if you know the simple array is all you'll ever need.
Probably the biggest issue is just that – breaking data encapsulation. Consider whether or not an abstraction such as an explicit iterator type would buy you anything versus the cost.
Does this always work for containers that have linear storage?
Yes, the iterator concepts were designed so that pointers could act as iterators over arrays.
If they do work in this situation, why should I ever go through the hassle of implementing iterators anyway?
There's no good reason to define your own iterator type in this situation, unless you want to do something like bounds-checking which can't be done with a simple pointer.
One slight benefit would be that you could include nested typedefs for the iterator's traits, as some of the standard iterator types do; but using pointers these are available from std::iterator_traits<T*> anyway.
What are the negative issues of what I'm doing if this approach would always work? For one thing, I can see I'm breaking data encapsulation.
To make the interface more consistent with STL-style containers, you should define iterator and const_iterator types (typedef aliases for the pointers), and provide const overloads of begin and end; and perhaps cbegin and cend for C++11 compatiblity.
There are various other requirements that you might want to conform to; see section 23.2 of the C++ standard for the gory details. But in general, it's more important to make iterators conform to their requirements, since STL-style algorithms work with iterators rather than containers, and by using pointers you already conform to those requirements.
It happens that pointers provide the interface required of random access iterators (dereference, increment, addition, difference, etc) and can be treated just like iterators.
It should always work for containers with contiguous storage.
You might wish to create your own iterators for the same reason you use methods instead of all public data in your classes: To encapsulate what's happening with an interface you can modify if you need to. As long as you typedef your T* to an iterator type this is probably not a significant issue. Additionally some algorithms may benefit from an iterator that's tagged with the iterator type, which you can't do for simple pointer types.

Implementation of operator!= for Iter Class

Based on the implementation of Iter, I have difficulties to understand operator!= and don't understand why it doesn't check _p_vec?
This is the suggested implementation of operator!= that ONLY compares the _pos.
class Iter
{
public:
Iter (const IntVector* p_vec, int pos)
: _pos( pos )
, _p_vec( p_vec )
{ }
// these three methods form the basis of an iterator for use with
// a range-based for loop
bool operator!= (const Iter& other) const
{
return _pos != other._pos;
}
...
...
private:
int _pos;
const IntVector *_p_vec;
};
However, I think the correct way to do this as follows. In other words, we have to compare both _pos and _p_vec.
bool Iter::operator!= (const Iter& other) const
{
return _p_vec != other._p_vec || _pos != other._pos;
}
Question> Whose code is correct?
===Update on how std::vector works on comparison of iterator====
std::vector<int> vecOne { 1, 2, 3};
std::vector<int> vecTwo { 4, 5, 6};
auto iterOne = vecOne.begin();
std::advance(iterOne, 1);
auto iterTwo = vecTwo.begin();
std::advance(iterTwo, 1);
if ( iterOne == iterTwo)
std::cout << "iterOne == iterTwo" << std::endl;
else
std::cout << "iterOne != iterTwo" << std::endl;
Output is : iterOne != iterTwo
However,
std::vector<int> foo;
std::vector<int> bar;
if ( foo.begin() == bar.begin() )
std::cout << "foo.begin() == bar.begin()" << std::endl;
else
std::cout << "foo.begin() != bar.begin()" << std::endl;
Output is : foo.begin() == bar.begin()
GCC (version 4.7.1)
Also comparing the underlying container reference is an improvement to make sure that, for example, the begin() iterators of two different containers compare equal.
However, iterators of different containers are rarely compared (when using STL algorithms, they never will). So this might be considered an optimization. Think of a loop in which you step from begin() to end(), so the only iterators you are comparing are the "current" one and end(), which are of the same container.
Comparing iterators of standard containers (vector, etc.) is considered undefined behavior. Indeed, since they never are compared in (good) code (for example the standard algorithms), it doesn't have to define a behavior for such cases.
So the author of this Iter class might also want to come back to this point and say: "Comparing iterators of different vectors is undefined behavior."
This being said, if you want to ensure that you never compare iterators of different containers, leave out this check and maybe assert it for debug builds (but don't check it in release builds).
A good example where you might want to compare iterators of different containers is for linked lists, where you define the end of the list being a null pointer (or a pointer to a static null item instance). Consider the iterator being a pointer to a linked list item; in this case, the end() iterator is just a null pointer (or points to this null item). It is the same one for all containers, so you can't implement the check in your comparison method in such cases. Maybe this is one of the reasons why such a comparison isn't defined -- it should return "unequal" when comparing end iterators of different lists, but it can't.
As a general rule, users of iterators are not supposed to compare iterators from different containers. In the standard library, doing so is undefined behavior.
So assuming you are only trying to create iterators that are as robust as standard library ones, comparing the container is not required. However, if you have the pointer to container around, then it would be polite to check that the containers match at least in debug, then assert that you shouldn't be making this comparison.
You are free to check it in release as well, but if your iterator using code is also supposed to work with standard containers, then relying on iterators from different containers comparing not equal is not advised.
See comparing iterators from different containers for someone talking about how it is undefined behavior.

Difference between std::vector::front() and begin()

Help on vector says of front()
Returns a reference to the first element in the vector container.
Unlike member vector::begin, which returns an iterator to this same element, this > function returns a direct reference.
Help on vector says of begin()
Returns an iterator referring to the first element in the vector container.
Notice that unlike member vector::front, which returns a reference to the first element, > this function returns a random access iterator.
And this code outputs:
char arr[] = { 'A', 'B', 'C' };
vector<char> vec(arr, arr+sizeof(arr));
cout << "address of vec.front() " << (void*)&vec.front() << endl;
cout << "address of vec.begin() " << (void*)&vec.begin() << endl;
address of vec.front() 00401F90
address of vec.begin() 0030F494
I don't understand what 'direct reference' means? In the case of begin() isn't a random access iterator just a pointer?
Can someone please point out the difference?
According to Stroustrup in The C++ Programming Language, Section 16.3.3; think of front() as the first element and begin() as a pointer to the first element.
In the case of begin() isn't a random access iterator just a pointer?
No, an iterator has some pointer semantics, but it's actually a class.
And even if it was, that should answer the question. It's like asking why the address of a pointer isn't the same as the address of the object it points to.
You'd get the same value if you dereference the iterator, which will give you the first element:
&(*vec.begin())
because
*vec.begin() == vec.front()
For a vector, begin() and end() return random access iterators. They might return a plain pointer; that's okay, because it meets the requirements to be a random access iterator. In particular, you can write *begin() to get a reference to the first object in the sequence (assuming there is one). front() gives you a reference to the first object in the sequence, without going through the intermediate iterator. Like this:
vector<int> v;
v.push_back(3);
int i = *v.begin(); // i == 3
int j = v.front(); // j == 3
Assuming you have at least 1 element in the vector,
vec.front()
is the same as
*vec.begin()
To keep it clear in your mind, always try to remember the following two lines assuming that you have a vector from STL called v:
v.front() = * v.begin()
&&
v.back() = * v.end()
that means if you have a vector:
v = {1,2,3,4};
and you have an iterator called IT, and you want to access the first and the last element
you can either do:
IT = v.begin();
std::cout<<*IT<<std::endl; // output : 1
IT = v.end();
std::cout<<*IT<<std::endl; // output : 4
or you can easily do this:
std::cout<<v.front<<std::endl; // output : 1
std::cout<<v.back<<std::endl; // output : 4
both will print the same output, the difference is just between if you want to use an iterator or not.