Using the stdl::vector class you can use two sorts of iteration over the vector:

the .begin and .end way

GlifPtrVec_t::iterator Iter ;
for (Iter = m_Array.begin() ; Iter != m_Array.end() ; Iter++) {
CGlif* pGlif = *Iter ;
delete pGlif ;
}

or one I am more used to:

for (i = 0 ; i < m_Array.size() ; i++)
delete m_Array

are they both valid or should one be used in certain situations or...?

Recommended Answers

All 5 Replies

Ok, so, you mean what is the difference between:

for(GlifPtrVec_t::iterator it = m_Array.begin(); it != m_Array.end(); ++it)
  delete *it;

And:

for(int i = 0; i < m_Array.size(); ++i)
  delete m_Array[i];

You should think of iterators as pointers, that is what they are meant to mimic in a generic way (and they might often be actual pointers). So, say that m_Array_ptr is the raw bits pointer to the start of the array contained in the vector (with type char*), then the two loops translate to this:

char* it = m_Array_ptr;
while( it != m_Array_ptr_end ) {
  delete *it; 
  it += sizeof(Foo*); //assuming Foo* is the type contained in the vector.
};

and:

int i = 0;
for( i < m_Array.size() ) {
  delete *(m_Array_ptr + i * sizeof(Foo*));
  ++i;
};

The former (with iterators) will involve, in each iteration, one condition evaluation and one add-and-assign operation (with a fixed size value). The latter will involve, in each iteration, one condition evaluation, one multiplication, one addition, and one increment (which is basically the same as add-and-assign). It's pretty obvious which is the fastest.

On a style point of view, both are totally fine in the sense that all programmers are very familiar with either styles, and many use a mix of both. But generally, for good practice, it is preferable to use the iterator-based version. The reason is simple. If your loop is not doing random-access, you should stick to a sequential-access format. Obviously, if your loop requires random access, then whatever container you decide to use will provide the indexing operator [], and in terms of efficiency, both indexed version and iterator versions will be the same, so, in that case, use whichever you prefer. However, when you don't need random-access, i.e., you are just traversing the vector from start to finish, then, if you use the iterator version, and you later realize that you could use another container instead of a STL vector, and that new container might not be random-access, then you won't have to change anything. This is called the Requirement Minimization Principle, you don't want to impose any more requirements than needed (e.g. don't require that random-access be supported if you don't really need it).

commented: good info +2

Thanks for the ideas and explanation.

I do need random access so I will stick with [].

I understand the point about being able to use the same code with other stl classes, but if I change class I am going to have to change a lot of other things too!

However, when you don't need random-access, i.e., you are just traversing the vector from start to finish, then, if you use the iterator version, and you later realize that you could use another container instead of a STL vector, and that new container might not be random-access, then you won't have to change anything.

To be fair, that's not a common occurrence. I've been writing C++ for nearly two decades now (above average code, in my opinion), and not once have I needed to completely swap the originally chosen container class with a different one.

There's one case where I prefer using an index over an iterator during sequential access, and that's when I need the index for other purposes than direct access:

for (T::size_type i = 0; i < cont.size(); i++)
    out<< i <<": "<< cont[i] <<'\n';

Iterators can be used for this, but I don't think it's quite as clear:

for (T::const_iterator i = cont.begin(); i != cont.end(); ++i)
    out<< i - cont.begin() <<": "<< *i <<'\n';

Here's an even more-complicated way to print the contents of a string.

std::string inputFirst = "Clearly.";
	std::copy(inputFirst.begin(),
		inputFirst.end(),
		std::ostream_iterator <std::string::value_type> (std::cout));

>>To be fair, that's not a common occurrence. I've been writing C++ for nearly two decades now (above average code, in my opinion), and not once have I needed to completely swap the originally chosen container class with a different one.

I guess experience differs. Maybe I have a more cowboyish way of doing some things, but it's not all that uncommon for me. I have done so several times in the past (e.g. for marginal cases where I'm not entirely sure if a vector or list or deque is the more efficient one, so I just test them all on the same generic algorithm that I am doing). I guess, if you are clever enough to always know beforehand which is better, you won't need to do that (but I'm not that clever).

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.