2544. istreambuf_iterator(basic_streambuf<charT, traits>* s) effects unclear when s is 0

Section: 24.6.4.3 [istreambuf.iterator.cons] Status: C++17 Submitter: S. B. Tam Opened: 2015-10-05 Last modified: 2017-07-30

Priority: 3

View all issues with C++17 status.

Discussion:

N4527 24.6.4.3 [istreambuf.iterator.cons] does not mention what the effect of calling istreambuf_iterator(basic_streambuf<charT, traits>* s) is when s is a null pointer. It should be made clear that this case is well-formed and the result is a end-of-stream iterator.

Daniel:

According to 24.6.4 [istreambuf.iterator] p1:

[…] The default constructor istreambuf_iterator() and the constructor istreambuf_iterator(0) both construct an end-of-stream iterator object suitable for use as an end-of-range. […]

This indicates that the described constructor creates an end-of-stream iterator, but this wording is part of the introductory wording and I recommend to make 24.6.4.3 [istreambuf.iterator.cons] clearer, because the existing specification is already flawed, e.g. it never specifies when and how the exposition-only-member sbuf_ is initialized. The proposed wording below attempts to solve these problems as well.

Previous resolution [SUPERSEDED]:

This wording is relative to N4527.

  1. Change 24.6.4.3 [istreambuf.iterator.cons] as indicated:

    [Editorial note: The proposed wording changes also performs some editorial clean-up of the existing mismatches of the declarations in the class template synopsis and the individual member specifications. The below wording intentionally does not say anything about the concrete value of sbuf_ for end-of-stream iterator values, because that was never specified before; in theory, this could be some magic non-null pointer that can be used in constant expressions. But the wording could be drastically simplified by requiring sbuf_ to be a null pointer for an end-of-stream iterator value, since I have not yet seen any implementation where this requirement does not hold. — end editorial note]

    constexpr istreambuf_iterator() noexcept;
    

    -1- Effects: Constructs the end-of-stream iterator.

    istreambuf_iterator(basic_istream<charT,traits>istream_type& s) noexcept;
    istreambuf_iterator(basic_streambuf<charT,traits>* s) noexcept;
    

    -2- Effects: If s.rdbuf() is a null pointer, constructs an end-of-stream iterator; otherwise initializes sbuf_ with s.rdbuf() and constructs an istreambuf_iterator that uses the streambuf_type object *sbuf_Constructs an istreambuf_iterator<> that uses the basic_streambuf<> object *(s.rdbuf()), or *s, respectively. Constructs an end-of-stream iterator if s.rdbuf() is null.

    istreambuf_iterator(streambuf_type* s) noexcept;
    

    -?- Effects: If s is a null pointer, constructs an end-of-stream iterator; otherwise initializes sbuf_ with s and constructs an istreambuf_iterator that uses the streambuf_type object *sbuf_.

    istreambuf_iterator(const proxy& p) noexcept;
    

    -3- Effects: Initializes sbuf_ with p.sbuf_ and constructs an istreambuf_iterator that uses the streambuf_type object *sbuf_Constructs a istreambuf_iterator<> that uses the basic_streambuf<> object pointed to by the proxy object's constructor argument p.

[2015-10-20, Daniel provides alternative wording]

[2016-08-03 Chicago]

Fri AM: Moved to Tentatively Ready

Proposed resolution:

This wording is relative to N4606.

  1. Change 24.6.4.3 [istreambuf.iterator.cons] as indicated:

    [Drafting note: The proposed wording changes also performs some editorial clean-up of the existing mismatches of the declarations in the class template synopsis and the individual member specifications. The below wording is simplified by requiring sbuf_ to be a null pointer for an end-of-stream iterator value, since I have not yet seen any implementation where this requirement does not hold. Even if there were such an implementation, this would still be conforming, because concrete exposition-only member values are not part of public API. — end drafting note]

    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.

    constexpr istreambuf_iterator() noexcept;
    

    -1- Effects: Initializes sbuf_ with nullptrConstructs the end-of-stream iterator.

    istreambuf_iterator(basic_istream<charT,traits>istream_type& s) noexcept;
    istreambuf_iterator(basic_streambuf<charT,traits>* s) noexcept;
    

    -2- Effects: Initializes sbuf_ with s.rdbuf()Constructs an istreambuf_iterator<> that uses the basic_streambuf<> object *(s.rdbuf()), or *s, respectively. Constructs an end-of-stream iterator if s.rdbuf() is null.

    istreambuf_iterator(streambuf_type* s) noexcept;
    

    -?- Effects: Initializes sbuf_ with s.

    istreambuf_iterator(const proxy& p) noexcept;
    

    -3- Effects: Initializes sbuf_ with p.sbuf_Constructs a istreambuf_iterator<> that uses the basic_streambuf<> object pointed to by the proxy object's constructor argument p.