Reputation: 485
There are so many alternative ways of addressing elements of a vector.
I could use a pointer like so:
vector<int> v = {10, 11, 12};
int *p = &v[0];
cout << *p; //Outputs "10"
I could use a pointer this way too:
vector<int> v = {10, 11, 12};
vector<int>::pointer p = v.data();
cout << *p; //Outputs "10"
I could also use the iterator type:
vector<int> v = {10, 11, 12};
vector<int>::iterator i = v.begin();
cout << *i; //Outputs "10"
Are there any significant differences that I'm missing here?
Upvotes: 24
Views: 12178
Reputation: 238
According to cppreference:
A pointer to an element of an array satisfies all requirements of LegacyContiguousIterator
which is the most powerful iterator as it encompasses all other iterators functionality. So they can be one and the same, an iterator is just a means of making our code clear, consice and portable.
For example we could have some container "C"...
//template <typename T, int N> class C { //for static allocation
template <typename T> class C {
//T _data[N]; //for static allocation
T* _data; //need to dynamically allocate _data
public:
typedef T* iterator;
}
where C<int>::iterator
would be an int*
and there would be no difference.
Maybe we don't want/need the full power of a LegacyContiguousIterator so we could redefine C<int>::iterator
as another class that follows the outline for say LegacyForwardIterator. This new iterator class may redefine operator*
. In this case it is implementation dependant and an int*
may cause undefined behaviour when trying to access the elements.
This is why iterators should be preferred but in most cases they are going to be the same thing.
In both cases our container " C" will work just like other STL containers so long as we define all the other necessary member functions and typedefs.
Upvotes: 0
Reputation: 110658
As far as being able to perform the task at hand, they all work equally well. After all, they all provide an object which meets the requirements of an iterator and you are using them to point at the same element of the vector
. However, I would pick the vector<int>::iterator
option because the type is more expressive about how we intend to use it.
The raw pointer type, int*
, tells you very little about what p
is, except that it stores the address of an int
. If you think about p
in isolation, its type doesn't tell you very much about how you can use it. The vector<int>::pointer
option has the same issue - it just expresses the type of the objects it points at as being the element type of a vector. There's no reason it actually needs to point into a vector
.
On the other hand vector<int>::iterator
tells you everything you need to know. It explicitly states that the object is an iterator and that iterator is used to point at elements in a vector<int>
.
This also has the benefit of being more easily maintainable if you ever happen to change the container type. If you changed to a std::list
, for example, the pointer type just wouldn't work any more because the elements are not stored as a contiguous array. The iterator
type of a container always provides you with a type you can use to iterate over its elements.
When we have Concepts, I'd expect the best practise to be something like:
ForwardIteratorOf<int> it = std::begin(v);
where ForwardIteratorOf<int>
(which I am imagining exists) is changed to whatever concept best describes your intentions for it
. If the type of the elements doesn't matter, then just ForwardIterator
(or BidirectionalIterator
, RandomAccessIterator
, or whatever).
Upvotes: 14
Reputation: 206577
If you add the check:
if ( !v.empty() )
Then, all the example you've shown are equally valid.
If you are about to iterate over the elements of the vector
, I would go with:
vector<int>::iterator i = v.begin();
It's easier to check whether the iterator has reached the end of the vector with an iterator than with the other forms.
if ( i != v.end() )
{
// Do stuff.
}
Upvotes: 4
Reputation: 17415
All these ways have their advantages, but at the core they are very similar. Some of them don't work though (they cause so-called "undefined behaviour") when the vector is empty.
Upvotes: 1