Checking if an iterator is valid

后端 未结 11 542
耶瑟儿~
耶瑟儿~ 2020-11-30 02:52

Is there any way to check if an iterator (whether it is from a vector, a list, a deque...) is (still) dereferencable, i.e. has not been invalidated?

I have been usi

相关标签:
11条回答
  • 2020-11-30 03:33

    I assume you mean "is an iterator valid," that it hasn't been invalidated due to changes to the container (e.g., inserting/erasing to/from a vector). In that case, no, you cannot determine if an iterator is (safely) dereferencable.

    0 讨论(0)
  • 2020-11-30 03:34

    Usually you test it by checking if it is different from the end(), like

    if (it != container.end())
    {
       // then dereference
    }
    

    Moreover using exception handling for replacing logic is bad in terms of design and performance. Your question is very good and it is definitively worth a replacement in your code. Exception handling like the names says shall only be used for rare unexpected issues.

    0 讨论(0)
  • 2020-11-30 03:36

    Non-portable answer: Yes - in Visual Studio

    Visual Studio's STL iterators have a "debugging" mode which do exactly this. You wouldn't want to enable this in ship builds (there is overhead) but useful in checked builds.

    Read about it on VC10 here (this system can and in fact does change every release, so find the docs specific to your version).

    Edit Also, I should add: debug iterators in visual studio are designed to immediately explode when you use them (instead undefined behavior); not to allow "querying" of their state.

    0 讨论(0)
  • 2020-11-30 03:37

    Is there any way to check if an iterator is dereferencable

    Yes, with gcc debugging containers available as GNU extensions. For std::list you can use __gnu_debug::list instead. The following code will abort as soon as invalid iterator is attempted to be used. As debugging containers impose extra overhead they are intended only when debugging.

    #include <debug/list>
    
    int main() {
      __gnu_debug::list<int> l;
      for (int i = 1; i < 10; i++) {
        l.push_back(i * 10);
      }
    
      auto itd = l.begin();
      itd++;
      l.erase(itd);
    
      /* now, in other place.. check if itd points to somewhere meaningful */
      if (itd != l.end()) {
        //  blablabla
      }
    }
    
    $ ./a.out 
    /usr/include/c++/7/debug/safe_iterator.h:552:
    Error: attempt to compare a singular iterator to a past-the-end iterator.
    
    Objects involved in the operation:
        iterator "lhs" @ 0x0x7ffda4c57fc0 {
          type = __gnu_debug::_Safe_iterator<std::_List_iterator<int>, std::__debug::list<int, std::allocator<int> > > (mutable iterator);
          state = singular;
          references sequence with type 'std::__debug::list<int, std::allocator<int> >' @ 0x0x7ffda4c57ff0
        }
        iterator "rhs" @ 0x0x7ffda4c580c0 {
          type = __gnu_debug::_Safe_iterator<std::_List_iterator<int>, std::__debug::list<int, std::allocator<int> > > (mutable iterator);
          state = past-the-end;
          references sequence with type 'std::__debug::list<int, std::allocator<int> >' @ 0x0x7ffda4c57ff0
        }
    Aborted (core dumped)
    
    0 讨论(0)
  • 2020-11-30 03:39

    Is there any way to check if a iterator (whether it is from a vector, a list, a deque...) is (still) dereferencable, i.e has not been invalidated ?

    No, there isn't. Instead you need to control access to the container while your iterator exists, for example:

    • Your thread should not modify the container (invalidating the iterator) while it is still using an instantiated iterator for that container

    • If there's a risk that other threads might modify the container while your thread is iterating, then in order to make this scenario thread-safe your thread must acquire some kind of lock on the container (so that it prevents other threads from modifying the container while it's using an iterator)

    Work-arounds like catching an exception won't work.

    This is a specific instance of the more general problem, "can I test/detect whether a pointer is valid?", the answer to which is typically "no, you can't test for it: instead you have to manage all memory allocations and deletions in order to know whether any given pointer is still valid".

    0 讨论(0)
提交回复
热议问题