istream_iterator
copy constructor trivial is an ABI breakSection: 24.6.2.2 [istream.iterator.cons] Status: C++23 Submitter: Jonathan Wakely Opened: 2021-09-23 Last modified: 2023-11-22
Priority: 3
View all other issues in [istream.iterator.cons].
View all issues with C++23 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
. IfT
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.
Modify 24.6.2.2 [istream.iterator.cons] as indicated:
istream_iterator(const istream_iterator& x) = default;-5- Postconditions:
in_stream == x.in_stream
istrue
.-6- Remarks: Ifis_trivially_copy_constructible_v<T>
istrue
, 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.
Modify the class synopsis in 24.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;Modify 24.6.2.2 [istream.iterator.cons] as indicated:
constexpr istream_iterator(const istream_iterator& x)= default;-5- Postconditions:
in_stream == x.in_stream
istrue
.-6- Remarks:
IfIf the initializeris_trivially_copy_constructible_v<T>
istrue
, then this constructor is trivial.T(x.value)
in the declarationauto 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.
Modify the class synopsis in 24.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;
Modify 24.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
istrue
.-?- Effects: Initializes
in_stream
withx.in_stream
and initializesvalue
withx.value
.-6- Remarks:
IfAn invocation of this constructor may be used in a core constant expression if and only if the initialization ofis_trivially_copy_constructible_v<T>
istrue
, then this constructor is trivial.value
fromx.value
is a constant subexpression ([defns.const.subexpr]). The exception specification is equivalent tois_nothrow_copy_constructible_v<T>
.