0

A bit of an elementary question, I'm looking for an STL container suited to the following types of uses:

1) Supports regular forward iteration

2) Supports deletion from middle of list while walking backwards through the list, and

3) If something gets deleted while walking backwards, I need to stop and walk forwards to the end of the list.

I used a regular std::list and found walking forward from a point in the list to be a little difficult, but doable. I used a combination of forward and reverse_iterator, and managed to avoid using advance (because that would be expensive!)

Here is my code.

#include <list>
using namespace std ;

int main()
{
  list< int > os ;
  os.push_back( 1 ) ;
  os.push_back( 2 ) ;
  os.push_back( 3 ) ;
  os.push_back( 4 ) ;
  os.push_back( 5 ) ;  

  // 1 2 3 4 5
  // should print:
  // 5: NOTHING
  // 4: 5
  // 3: 4,5
  // 2: 3,4,5
  // 1: 2,3,4,5
  for( list<int>::reverse_iterator riter = os.rbegin() ; riter != os.rend() ; ++riter )
  {
    //printf( "All the ones in FRONT of %d are:\n", riter->a ) ;
    printf( "%d:  ", *riter ) ;

    // You can't do it with a for loop.
    //for( list<O>::reverse_iterator iter = riter ; iter != os.rbegin() ; --iter )

    list<int>::reverse_iterator iter = riter ;

    if( iter != os.rbegin() ) do
    {
      --iter ; // move the iterator back.
      printf( " %d", *iter ) ;
    } while ( iter != os.rbegin() ) ;
    //else printf( " NOTHING AFTER ME" ) ;

    puts("");
  }
}

My questions are:

  • Have I made a bad choice of container? Should I have used deque instead?
  • Was there a way to do it using for instead of do/while in the inner loop?
DavidO
  • 13,812
  • 3
  • 38
  • 66
bobobobo
  • 64,917
  • 62
  • 258
  • 363

1 Answers1

1

Considering your requirements, I believe your choice of list is good (but it's std::list, not stl::list).

A removal from the middle of a vector would invalidate all pointers, references, and iterators to elements previous to the removed one; a removal from the middle of a deque would invalidate all pointers, references, and iterators.

Removal from a list, on the other hand, is guaranteed to invalidate only iterators to the element(s) you remove, so if you take proper care when removing an element you can keep iterating forward and backward.

Considering your loop, I can't help pointing out that:

if (C) do { ... } while (C)

Is equivalent to the more elegant (IMO):

while (C) do { ... }
Andy Prowl
  • 124,023
  • 23
  • 387
  • 451
  • I don't agree that the requirements suggest std::list is the best choice. You can iterate forward/backward just as well with a std::vector, plus it's faster in practice. As for the invalidation, as a general rule I'd avoid keeping references/iterators to elements, especially in a container that is modified at run time, and prefer to use the container's accessors. – congusbongus Feb 07 '13 at 00:59
  • It's true that under most conditions std::vector is faster, but you wouldn't be answering the question IMO. The OP asked if *given his requirements* his choice was ok, and i think it is. I assume he has good reasons for having those requirements. You are basically asserting he shouldn't have those requirements, and I believe we don't know enough to tell that – Andy Prowl Feb 07 '13 at 01:10
  • Well removing from the middle of a `std::vector` is a no-no, it requires a total reallocation of the entire array – bobobobo Feb 07 '13 at 18:37
  • @bobobobo: Actually it does not: only adding more elements may result in a complete reallocation. Removal simply shifts all the subsequent elements by one place, which invalidates iterators, pointers, and references, but does not cause a reallocation. And due to move semantics and data locality (the elements are in a contiguous region of memory), which gives a very high cache hit rate, this often turns out to be faster than a list removal for small elements, or comparable at least. – Andy Prowl Feb 07 '13 at 18:44