How to read N integers into a vector?

后端 未结 2 1184
萌比男神i
萌比男神i 2020-12-29 06:24

If I want to read all integers from standard input to a vector, I can use the handy:

vector v{istream_iterator(cin), istream_i         


        
相关标签:
2条回答
  • 2020-12-29 06:44

    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)

    0 讨论(0)
  • 2020-12-29 06:47

    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

    0 讨论(0)
提交回复
热议问题