If I want to read all integers from standard input to a vector, I can use the handy:
vector<int> v{istream_iterator<int>(cin), istream_iterator()};
But let's assume I only want to read n
integers. Is the hand-typed loop everything I got?
vector<int> v(n);
for(vector<int>::size_type i = 0; i < n; i++)
cin >> v[i];
Or is there any more right-handed way to do this?
As given in comments, copy_n
is unsafe for this job, but you can use copy_if
with mutable lambda:
#include <iterator>
#include <vector>
#include <iostream>
#include <algorithm>
int main(){
const int N = 10;
std::vector<int> v;
//optionally v.reserve(N);
std::copy_if(
std::istream_iterator<int>(std::cin),
std::istream_iterator<int>(),
std::back_inserter(v),
[count=N] (int) mutable {
return count && count--;
});
return 0;
}
as pointed out in this answer:
std::copy n elements or to the end
You usually shouldn't do this with std::copy_n
, which assumes that the provided iterator, when incremented n times, remains valid:
Copies exactly count
values from the range beginning at first
to the range beginning at result
. Formally, for each non-negative integer i < n
, performs *(result + i) = *(first + i)
.
(cppreference.com article on std::copy_n
)
If you can guarantee that, then fine, but generally with std::cin
that's not possible. You can quite easily have it dereferencing an invalid iterator:
The default-constructed std::istream_iterator
is known as the end-of-stream iterator. When a valid std::istream_iterator
reaches the end of the underlying stream, it becomes equal to the end-of-stream iterator. Dereferencing or incrementing it further invokes undefined behavior.
(cppreference.com article on std::istream_iterator
)
You're pretty much there with your loop, though I'd probably use stronger termination condition to avoid excess reads from a "dead" stream:
vector<int> v(n);
for(vector<int>::size_type i = 0; i < n; i++)
if (!cin >> v[i])
break;
I'd be tempted actually to wrap this into something that's like std::copy_n
, but accepts a full "range" whose bounds may be validated in addition to counting from 0 to N.
An implementation might look like:
template<class InputIt, class Size, class OutputIt>
OutputIt copy_atmost_n(InputIt first, InputIt last, Size count, OutputIt result)
{
for (Size i = 0; i < count && first != last; ++i)
*result++ = *first++;
return result;
}
You'd use it like this:
copy_atmost_n(
std::istream_iterator<int>(std::cin),
std::istream_iterator<int>(),
N,
std::back_inserter(v)
);
Now you get M elements, where M is either the number of inputs provided or N, whichever is smaller.
(live demo)