c++stringiteratorchar-pointerconst-pointer

Prefer Iterators Over Pointers?


This question is a bump of a question that had a comment here but was deleted as part of the bump.

For those of you who can't see deleted posts, the comment was on my use of const char*s instead of string::const_iterators in this answer: "Iterators may have been a better path from the get go, since it appears that is exactly how your pointers seems be treated."

So my question is this, do iterators hold string::const_iterators hold any intrinsic value over a const char*s such that switching my answer over to string::const_iterators makes sense?


Solution

  • Introduction

    There are many perks of using iterators instead of pointers, among them are:



    Debugging

    Since, among other things, dereferencing an iterator that is passed the end of a range is undefined-behavior, an implementation is free to do whatever it feels necessary in such case - including raising diagnostics saying that you are doing something wrong.

    The standard library implementation, libstdc++, provided by gcc will issues diagnostics when it detects something fault (if Debug Mode is enabled).


    Example

    #define _GLIBCXX_DEBUG 1 /* enable debug mode */
    
    #include <vector>
    #include <iostream>
    
    int
    main (int argc, char *argv[])
    {
      std::vector<int> v1 {1,2,3};
    
      for (auto it = v1.begin (); ; ++it)
        std::cout << *it;
    }
    
    /usr/include/c++/4.9.2/debug/safe_iterator.h:261:error: attempt to 
        dereference a past-the-end iterator.
    
    Objects involved in the operation:
    iterator "this" @ 0x0x7fff828696e0 {
    type = N11__gnu_debug14_Safe_iteratorIN9__gnu_cxx17__normal_iteratorIPiNSt9__cxx19986vectorIiSaIiEEEEENSt7__debug6vectorIiS6_EEEE (mutable iterator);
      state = past-the-end;
      references sequence with type `NSt7__debug6vectorIiSaIiEEE' @ 0x0x7fff82869710
    }
    123
    

    The above would not happen if we were working with pointers, no matter if we are in debug-mode or not.

    If we don't enable debug mode for libstdc++, a more performance friendly version (without the added bookkeeping) implementation will be used - and no diagnostics will be issued.



    (Potentially) better Type Safety

    Since the actual type of iterators are implementation-defined, this could be used to increase type-safety - but you will have to check the documentation of your implementation to see whether this is the case.


    Consider the below example:

    #include <vector>
    

    struct A     { };
    struct B : A { };
    

                                                          // .-- oops
                                                          // v
    void  it_func (std::vector<B>::iterator beg, std::vector<A>::iterator end);
    
    void ptr_func (B * beg, A * end);
                         // ^-- oops
    

    int
    main (int argc, char *argv[])
    {
      std::vector<B> v1;
    
       it_func (v1.begin (), v1.end  ());               // (A)
      ptr_func (v1.data  (), v1.data () + v1.size ());  // (B)
    }
    

    Elaboration