How to check if the iterator is initialized?

前端 未结 11 1339
孤城傲影
孤城傲影 2021-02-05 06:30

If I use a default constructor for an iterator, how to check if it was assigned later on?

For pointers, I could do this :

int *p = NULL;
/// some code
         


        
相关标签:
11条回答
  • 2021-02-05 07:22

    I used the following solution:

    const MyList_t::const_iterator NullIterator(NULL);
    const_iterator MyList_t::MyIterator;
    

    Then a check is possible:

    if (NullIterator != MyIterator) {}
    
    0 讨论(0)
  • 2021-02-05 07:23

    I managed to find this in the current standard (c++03 ). 24.1 p 5 tells :

    Just as a regular pointer to an array guarantees that there is a pointer value pointing past the last element of the array, so for any iterator type there is an iterator value that points past the last element of a corresponding container. These values are called past-the-end values. Values of an iterator i for which the expression *i is defined are called dereferenceable. The library never assumes that past-the-end values are dereferenceable. Iterators can also have singular values that are not associated with any container. [Example: After the declaration of an uninitialized pointer x (as with int* x;), x must always be assumed to have a singular value of a pointer. ] Results of most expressions are undefined for singular values; the only exception is an assignment of a non-singular value to an iterator that holds a singular value. In this case the singular value is overwritten the same way as any other value. Dereferenceable values are always non- singular.

    (Emphasis mine)

    So the answer is : no, it is not possible.

    0 讨论(0)
  • 2021-02-05 07:29

    The best way to do this I can think of is something like

    #include <utility>
    #include <map>
    #include <typeinfo>
    #include <string>
    
    
    
    namespace nulliterators {
    
    typedef std::map<std::string, void*> nullcntT;
    nullcntT nullcontainers;
    
    template<class containerT>
    typename containerT::iterator iterator() {
      containerT* newcnt = new containerT();
      std::string cnttypename = typeid(*newcnt).name();
      nullcntT::iterator i = nullcontainers.find(cnttypename);
      if (i==nullcontainers.end()) {
        nullcontainers.insert(make_pair(cnttypename, newcnt));
        return newcnt->end();
       }else{
        delete newcnt;
        return (static_cast<containerT*>(i->second))->end();
      }
    }
    
    }
    template<class containerT>
    typename containerT::iterator nulliterator() { return nulliterators::iterator<containerT>(); }
    
    
    #include <list>
    #include <iostream>
    
    
    int main(){
    
      std::list<int>::iterator nullinitized = nulliterator< std::list<int> >();
      std::list<int> somelist;
      std::list<int>::iterator initialized = somelist.end();
    
      if (nullinitized == nulliterator< std::list<int> >())
        std::cout << "nullinitized == nulliterator< std::list<int> >()\n";  //true
       else
        std::cout << "nullinitized != nulliterator< std::list<int> >()\n";
    
      if (initialized == nulliterator< std::list<int> >())
        std::cout << "initialized == nulliterator< std::list<int> >()\n";
       else
        std::cout << "initialized != nulliterator< std::list<int> >()\n";  //true
    
      return 0;
    }
    

    but it's not exactly a safe solution (because it relies on the non-const global containers in nullcontainers).

    0 讨论(0)
  • 2021-02-05 07:30

    This question has already been treated in Stackoverflow. The quintessence is that the default constructor initializes an iterator to a singular value, and the only addmissible operation on it is to assign it another iterator value. In particular it is not possible to query the value of such unitialized iterator. Therefore it is a good programming practice to initialize the iterator to a specific value of a specific container, which then can be tested for.

    0 讨论(0)
  • 2021-02-05 07:34

    Since there is no default value for iterators (like there is NULL for pointers), in situation where i need a common default value for a Object::iterator (before any actual Object has been created) I create a dummy static variable and use its ::end() as the default.

    Update : This only works for Release, because in DEBUG (or with _HAS_ITERATOR_DEBUGGING=1) comparison operators check if both iterators point to the same object/container.

    For example for vector<int> I would do :

    class A
    {
    public :
        A() :  myIterator1(dummyVector.end()), myIterator2(dummyVector.end()) {}
        // needed iterators
        vector<int>::iterator myIterator1;
        vector<int>::iterator myIterator2;
    
        static const vector<int> dummyVector;
    }
    
    #define  IT_NULL A::dummyObject.end()
    
    void maint() {
        A::dummyObject = vector<int>(); // initialize the Null iterator
    
        A a;
        if(a.myIterator1 == IT_NULL) cout << "Iterator not yet initialized";
    }
    
    0 讨论(0)
提交回复
热议问题