[Bug libstdc++/64814] New: std::copy_n advances InputIterator one *less* time than necessary.
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=64814 Bug ID: 64814 Summary: std::copy_n advances InputIterator one *less* time than necessary. Product: gcc Version: 4.9.2 Status: UNCONFIRMED Severity: major Priority: P3 Component: libstdc++ Assignee: unassigned at gcc dot gnu.org Reporter: alex-j-a at hotmail dot co.uk Bug 50119 is related. The issue should be clear from the example below; I've confirmed the output on several web-based compilers (I'm using a chromebook in standard config) all of which claim to use GCC. minimal failing example: #include #include #include #include #include int main() { std::istringstream ss("123456789012"); std::string output; auto readIter = std::istreambuf_iterator(ss); for (int i = 0; i < 3; ++i) { output.clear(); auto inserter = std::back_inserter(output); // Works - outputs 123456789012 //for (int j = 0; j < 4; ++j) //*inserter++ = *readIter++; // Doesn't work - outputs 123445677890 std::copy_n(readIter, 4, inserter); std::cout << output; } } The following works perfectly as a drop-in replacement from my tests: template OutputIt copy_n(InputIt first, SizeT count, OutputIt result) { for (; count > 0; --count) *result++ = *first++; return result; }
[Bug libstdc++/64814] std::copy_n advances InputIterator one *less* time than necessary.
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=64814 --- Comment #2 from Anquietas --- (In reply to Jonathan Wakely from comment #1) > The problem is that increments to the input iterator happen inside > the copy_n call, to a copy of the iterator not to readIter itself. The copy_n implementation I provided produces the same behaviour as the for loop, even with copying the iterator.
[Bug libstdc++/64814] std::copy_n advances InputIterator one *less* time than necessary.
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=64814 --- Comment #5 from Anquietas --- (In reply to Jonathan Wakely from comment #3) > However, I don't see any requirement in the standard that says we're > supposed to do so. All that is required is n assignments, there is no > guarantee that the input range is also incremented past the last element > written to. The closest thing I could find to an up to date copy of the C++11 standard: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3337.pdf copy_n is on page 851 "Effects: For each non-negative integer i < n, performs *(result + i) = *(first + i)." Since it's talking about input iterators where (first + n) isn't valid I think we can interpret this as n applications each of ++first and *first. I don't know whether the most recent version changed the description though; perhaps if you could provide a link?
[Bug libstdc++/64814] std::copy_n advances InputIterator one *less* time than necessary.
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=64814 --- Comment #6 from Anquietas --- (In reply to Anquietas from comment #5) http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4296.pdf The working copy for C++14, page 902 has the same specification as the other PDF.
[Bug libstdc++/64814] std::copy_n advances InputIterator one *less* time than necessary.
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=64814 --- Comment #9 from Anquietas --- (In reply to Jonathan Wakely from comment #8) > N.B. libc++ changed its copy_n with > http://lists.cs.uiuc.edu/pipermail/cfe-commits/Week-of-Mon-20110221/039404. > html and then libstdc++ did the same in PR 50119 I linked that bug report in the OP, but as it happens the behaviour is quite interesting with std::istream_iterator using an adaptation of the code I pasted in OP: int main() { std::istringstream ss("1 2 3 4 5 6 7 8 9 0 1 2 "); std::vector output; auto readIter = std::istream_iterator(ss); for (int i = 0; i < 3; ++i) { output.clear(); auto inserter = std::back_inserter(output); // Doesn't work - outputs 123415671890 std::copy_n(readIter, 4, inserter); for (auto n : output) std::cout << n; } } However, in this case moving readIter's declaration inside the loop fixes it. If we go back to the code in OP and do the same, it *doesn't* fix it and still produces the same output in either case. At the very least, the current implementation of copy_n appears to be inconsistent, depending on the type of iterator used. The implementation I provided for copy_n in OP doesn't work for the istream_iterator case though, and neither does the direct for loop approach.