This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of New status.

2366. istreambuf_iterator end-of-stream equality

Section: 24.6.4 [istreambuf.iterator] Status: New Submitter: Hyman Rosen Opened: 2014-02-19 Last modified: 2023-04-13

Priority: 3

View other active issues in [istreambuf.iterator].

View all other issues in [istreambuf.iterator].

View all issues with New status.

Discussion:

Given the following code,

#include <sstream>

std::stringbuf buf;
std::istreambuf_iterator<char> begin(&buf);
std::istreambuf_iterator<char> end;

it is not clear from the wording of the Standard whether begin.equal(end) must be true. In at least one implementation it is not (CC: Sun C++ 5.10 SunOS_sparc Patch 128228-25 2013/02/20) and in at least one implementation it is (gcc version 4.3.2 x86_64-unknown-linux-gnu).

24.6.4 [istreambuf.iterator] says that end is an end-of-stream iterator since it was default constructed. It also says that an iterator becomes equal to an end-of-stream iterator when end of stream is reached by sgetc() having returned eof(). [istreambuf.iterator::equal] says that equal() returns true iff both iterators are end of stream or not end of stream. But there seems to be no requirement that equal check for end-of-stream by calling sgetc().

Jiahan Zi at BloombergLP discovered this issue through his code failing to work correctly. Dietmar Kühl has opined in a private communication that the iterators should compare equal.

[2023-03-31; Jonathan Wakely comments]

I agree that they should compare equal, but that's in conflict with the resolution of LWG 2544(i), which says that begin must not be at end-of-stream because &buf is not null.

[2023-04-12; Jonathan adds wording]

Proposed resolution:

This wording is relative to N4944.

  1. Change 24.6.4.1 [istreambuf.iterator.general] as indicated:

    
        constexpr istreambuf_iterator() noexcept;
        constexpr istreambuf_iterator(default_sentinel_t) noexcept;
        istreambuf_iterator(const istreambuf_iterator&) noexcept = default;
        ~istreambuf_iterator() = default;
        istreambuf_iterator(istream_type& s) noexcept;
        : istreambuf_iterator(s.rdbuf()) { }
        istreambuf_iterator(streambuf_type* s) noexcept;
        istreambuf_iterator(const proxy& p) noexcept;
        
    
      private:
        streambuf_type* sbuf_;              // exposition only
        int_type c_{};                      // exposition only
      };
    }
    
  2. Change 24.6.4.3 [istreambuf.iterator.cons] as indicated:

    For each istreambuf_iterator constructor in this section, an end-of-stream iterator is constructed if and only if the exposition-only member sbuf_ is initialized with a null pointer value or if sbuf_->sgetc() returns traits_type::eof().

    constexpr istreambuf_iterator() noexcept;
    constexpr istreambuf_iterator(default_sentinel_t) noexcept;
    

    -1- Effects: Initializes sbuf_ with nullptr.

    istreambuf_iterator(istream_type& s) noexcept;

    -2- Effects: Initializes sbuf_ with s.rdbuf().

    istreambuf_iterator(streambuf_type* s) noexcept;
    

    [Drafting note: sgetc() can throw, but this function is noexcept. Should it swallow exceptions and create an end-of-stream iterator, to avoid weakening the exception spec of an existing function?]

    -3- Effects: Initializes sbuf_ with s. If s is not null, initializes c_ with s->sgetc(). Sets sbuf_ to null if sgetc exits via an exception, or if traits_type::eq_int_type(c_, traits_type::eof()) is true.

    istreambuf_iterator(const proxy& p) noexcept;
    

    -4- Effects: Initializes sbuf_ with p.sbuf_. If p.sbuf_ is not null, initializes c_ with p.keep_.

  3. Change 24.6.4.4 [istreambuf.iterator.ops] as indicated:

    charT operator*() const;
    

    -?- Preconditions: sbuf_ is not null.

    -1- Returns: The character obtained via the streambuf member sbuf_->sgetc(). traits_type::to_char_type(c_).

    -?- Throws: Nothing.

    istreambuf_iterator& operator++();
    

    -?- Preconditions: sbuf_ is not null.

    -2- Effects: As if by sbuf_->sbumpc(). Performs c_ = sbuf_->snextc(), then sets sbuf_ to null if traits_type::eq_int_type(c_, traits_type::eof()) is true.

    -3- Returns: *this.

    proxy operator++(int);
    

    -4- Returns: proxy(sbuf_->sbumpc(), sbuf_).
    Effects: Equivalent to:

    proxy p(**this, sbuf_);
    ++*this;
    return p;
    

    bool equal(const istreambuf_iterator& b) const;
    

    -5- Returns: bool(sbuf_) == bool(b.sbuf_).

    [Note: This is true if and only if both iterators are at end-of-stream, or neither is at end-of-stream, regardless of what streambuf object they use. end note]

    template<class charT, class traits>
      bool operator==(const istreambuf_iterator<charT, traits>& a,
                      const istreambuf_iterator<charT, traits>& b);
    

    -6- Returns: a.equal(b).

    bool equal(const istreambuf_iterator& i, default_sentinel_t s) const;
    

    -7- Returns: i.equal(s) i.sbuf_ == nullptr.

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy