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

### 3600. Making `istream_iterator` copy constructor trivial is an ABI break

Section: 25.6.2.2 [istream.iterator.cons] Status: WP Submitter: Jonathan Wakely Opened: 2021-09-23 Last modified: 2022-11-17

Priority: 3

View all other issues in [istream.iterator.cons].

View all issues with WP status.

Discussion:

Libstdc++ never implemented this change made between C++03 and C++11 (by N2994):

24.6.1.1 [istream.iterator.cons] p3:

>     istream_iterator(const istream_iterator<T,charT,traits,Distance>& x) = default;

> > -3- Effects: Constructs a copy of `x`. If `T` is a literal type, then this constructor shall be a trivial copy constructor.

This breaks our ABI, as it changes the argument passing convention for the type, meaning this function segfaults if compiled with today's libstdc++ and called from one that makes the triviality change:

>     #include <iterator>
>     #include <istream>

>     int f(std::istream_iterator<int> i)
>     {
>       return *i++;
>     }

As a result, it's likely that libstdc++ will never implement the change.

There is no reason to require this constructor to be trivial. It was required for C++0x at one point, so the type could be literal, but that is not true in the current language. We should strike the requirement, to reflect reality. MSVC and libc++ are free to continue to define it as defaulted (and so trivial when appropriate) but we should not require it from libstdc++. The cost of an ABI break is not worth the negligible benefit from making it trivial.

Previous resolution [SUPERSEDED]:

> This wording is relative to N4892.

> 1. Modify 25.6.2.2 [istream.iterator.cons] as indicated:

>    >     istream_iterator(const istream_iterator& x) = default;

>    > > -5- Postconditions: `in_stream == x.in_stream` is `true`.

>    > > -6- Remarks: If `is_trivially_copy_constructible_v<T>` is `true`, then this constructor is trivial.

[2021-09-30; Jonathan revises wording after reflector discussion]

A benefit of triviality is that it is constexpr, want to preserve that.

[2021-10-14; Reflector poll]

Set priority to 3 after reflector poll.

Previous resolution [SUPERSEDED]:

> This wording is relative to N4892.

> 1. Modify the class synopsis in 25.6.2.1 [istream.iterator.general] as indicated:

>    >     constexpr istream_iterator();
>    >     constexpr istream_iterator(default_sentinel_t);
>    >     istream_iterator(istream_type& s);
>    >     constexpr istream_iterator(const istream_iterator& x) = default;
>    >     ~istream_iterator() = default;
>    >     istream_iterator& operator=(const istream_iterator&) = default;

> 2. Modify 25.6.2.2 [istream.iterator.cons] as indicated:

>    >       constexpr istream_iterator(const istream_iterator& x) = default;

>    > > -5- Postconditions: `in_stream == x.in_stream` is `true`.

>    > > -6- Remarks: If `is_trivially_copy_constructible_v<T>` is `true`, then this constructor is trivial. If the initializer `T(x.value)` in the declaration `auto val = T(x.value);` is a constant initializer ([expr.const]), then this constructor is a constexpr constructor.

[2022-10-12; Jonathan provides improved wording]

Discussed on the reflector September 2021.

[2022-10-13; Jonathan revises wording to add a noexcept-specifier]

[2022-11-07; Reflector poll]

Set status to Tentatively Ready after six votes in favour during reflector poll.

[2022-11-12 Approved at November 2022 meeting in Kona. Status changed: Voting → WP.]

Proposed resolution:

This wording is relative to N4917.

1. Modify the class synopsis in 25.6.2.1 [istream.iterator.general] as indicated:

   >     constexpr istream_iterator();
   >     constexpr istream_iterator(default_sentinel_t);
   >     istream_iterator(istream_type& s);
   >     constexpr istream_iterator(const istream_iterator& x) noexcept(see below) = default;
   >     ~istream_iterator() = default;
   >     istream_iterator& operator=(const istream_iterator&) = default;

2. Modify 25.6.2.2 [istream.iterator.cons] as indicated:

   >       constexpr istream_iterator(const istream_iterator& x) noexcept(see below) = default;

   > > -5- Postconditions: `in_stream == x.in_stream` is `true`.

   > > -?- Effects: Initializes `in_stream` with `x.in_stream` and initializes `value` with `x.value`.

   > > -6- Remarks: If `is_trivially_copy_constructible_v<T>` is `true`, then this constructor is trivial. An invocation of this constructor may be used in a core constant expression if and only if the initialization of `value` from `x.value` is a constant subexpression ([defns.const.subexpr]). The exception specification is equivalent to `is_nothrow_copy_constructible_v<T>`.