[Bug libstdc++/64814] New: std::copy_n advances InputIterator one *less* time than necessary.

2015-01-26 Thread alex-j-a at hotmail dot co.uk
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.

2015-01-27 Thread alex-j-a at hotmail dot co.uk
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.

2015-01-27 Thread alex-j-a at hotmail dot co.uk
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.

2015-01-27 Thread alex-j-a at hotmail dot co.uk
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.

2015-01-29 Thread alex-j-a at hotmail dot co.uk
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.