Forums before death by AOL, social media and spammers... "We can't have nice things"
|    comp.lang.c++.moderated    |    Moderated discussion of C++ superhackery    |    33,346 messages    |
[   << oldest   |   < older   |   list   |   newer >   |   newest >>   ]
|    Message 33,150 of 33,346    |
|    =?ISO-8859-1?Q?Daniel_Kr=FCgler?= to All    |
|    Re: input iterators and post increment    |
|    25 Jul 13 07:56:40    |
   
   From: daniel.kruegler@googlemail.com   
      
   On 2013-07-25 15:53, fmatthew5876 wrote:   
   >> I don't understand what you mean. If your input iterator returns a   
   >> proxy result, there is no reason why this could cause the code to be   
   >> dangerous that could lead to random crashes. Would you please   
   >> elaborate?   
   >>   
   >   
   > But what value would the proxy object have? Set it to the value of   
   > the previous iterator?   
      
   As I explained in my first (corrected) response to you:   
      
   "we also need to satisfy the additional constraint that the expression   
      
   *r++   
      
   is valid and returns a type that is convertible to the value type of the   
   iterator. A typical solution is to return a proxy class that provides   
   operator* and that returns a copy of the referenced value before the   
   incrementation happened."   
      
   There is no need for the proxy to store the iterator (in fact, it really   
   should not store such a copy!), it suffices that it contains a copy of   
   the *value type* of the value *before* the incrementation happened. In   
   other words: For pure input iterators, the post-increment operator does   
   also dereference the current iterator to obtain its current value!   
      
   > Most importantly, where is it stored? In the   
   > iterator itself? Great, every iterator now grows by sizeof(T) just   
   > for this one case. As a static object? That wouldn't work for thread   
   > safety. On the heap? Now we're hitting the memory allocator. This   
   > is very slow, imagine if someone writes a post increment loop,   
   > correctly throwing away the result. Every increment now does a   
   > useless new and delete and nobody can even tell this is happening by   
   > just looking at the code. Also now you have to track ownership,   
   > handle moves/copies etc..   
      
   These arguments are all mood, given above explanation. There is no need   
   that input iterators have to reserve additional memory just to implement   
   a rarely used function.   
      
   > What happens if you increment the iterator holding   
   > a proxy? The madness goes on and on. Better to just crash and   
   > tell the programmer don't do that!   
      
   No need for that, really.   
      
   > Basically my iterator class looks like this.   
   >   
   > class Container::iterator {   
      
   I'm just realizing that you seem to have a container here. I'm not sure   
   whether it is one that corresponds to the requirements of a Standard   
   Library Container, but if so, they are required to return forward   
   iterators. But this is just a side commented not really related to your   
   actual problem at hand.   
      
   > public:   
   > iterator()   
   > : _first(nullptr), _last(nullptr), _parent(nullptr)   
   > T& operator*() { assert(_first != nullptr); return *_first; }   
   > T* operator->() { assert(_first != nullptr); return _first; }   
   > iterator& operator++() {   
   > assert(_first != nullptr);   
   > if(_first != _last) {   
   > ++_first;   
   > } else {   
   > _parent->giveMeMore(&_first, &_last);   
   > }   
   > return *this;   
   > }   
   > iterator operator++(int) {   
   > ++(*this);   
   > return iterator(); //<-asserts on dereference   
   > }   
      
   This is incorrectly implemented, because a user is allowed to   
   dereference the result of the postfix increment operation:   
      
   *iter++   
      
   is a supported operation. Instead return something like this:   
      
   struct proxy {   
    value_type& operator*() const {   
    return value;   
    }   
   private:   
    friend class Container::iterator;   
    explicit input_iterator_postfix_increment_result(   
    const Container::iterator& iter)   
    : value(*iter) { }   
    mutable value_type value;   
   };   
      
   and implement post-increment like this:   
      
    proxy operator++(int) {   
    proxy result(*this);   
    ++(*this);   
    return result;   
    }   
      
   > private:   
   > T* _first;   
   > T* _last;   
   > Container* _parent;   
   >   
   > friend class Container;   
   > iterator(T* f, T* l, Container *p)   
   > : _first(f), _last(l), _parent(p) {}   
   > };   
   >   
   > The standard allows for past iterators to become invalidated. Instead   
   > of waiting for this to happen by chance, I do it every time.   
   > Dereferencing a past input iterator in this case is a programmer   
   > error and thus should be caught and fixed as early as possible.   
      
   There is no need for such rigorous behaviour, because post-increment can   
   be implemented without such harmful effects.   
      
   >> It's inefficient for many non-pointer iterators, but it is not   
   >> dangerous. I don't think that an efficiency argument alone could   
   >> convince the committee to break code that exists since decades.   
   >   
   > It is dangerous for input/ouput iterators.   
      
   No, it isn't, if correctly implemented.   
      
   > It wouldn't break any code. The STL would simply stop calling   
   > post-increment if it ever does and always use pre-increment. Anyone   
   > who has correctly implemented an iterator has always implemented   
   > pre-increment and copy construction.   
      
   The "STL" is not the only user of the iterator requirements contract,   
   this contract is used in many third party libraries which rely on that   
   specification. Again, I think this should better be solved by a revised   
   set of iterator requirements instead of breaking the existing ones.   
      
   HTH & Greetings from Bremen,   
      
   - Daniel Krügler   
      
      
   --   
    [ See http://www.gotw.ca/resources/clcm.htm for info about ]   
    [ comp.lang.c++.moderated. First time posters: Do this! ]   
      
   --- SoupGate-Win32 v1.05   
    * Origin: you cannot sedate... all the things you hate (1:229/2)   
|
[   << oldest   |   < older   |   list   |   newer >   |   newest >>   ]
(c) 1994, bbs@darkrealms.ca