如果我想将标准输入的所有整数读入一个向量中,我可以使用以下便捷方式:
vector<int> v{istream_iterator<int>(cin), istream_iterator()};
假设我只想读取n
个整数,那么手动输入循环就是唯一的选择吗?
vector<int> v(n);
for(vector<int>::size_type i = 0; i < n; i++)
cin >> v[i];
还有其他右手操作的方法吗?
如果我想将标准输入的所有整数读入一个向量中,我可以使用以下便捷方式:
vector<int> v{istream_iterator<int>(cin), istream_iterator()};
假设我只想读取n
个整数,那么手动输入循环就是唯一的选择吗?
vector<int> v(n);
for(vector<int>::size_type i = 0; i < n; i++)
cin >> v[i];
还有其他右手操作的方法吗?
通常情况下,您不应该使用std::copy_n
进行此操作,因为它假定在将迭代器递增n次时,提供的迭代器仍然有效:
从以
first
开头的范围中复制count
个值到以result
开头的范围中。形式上,对于每个非负整数i < n
,执行*(result + i) = *(first + i)
。
如果您能够保证这一点,那么可以使用,但通常情况下,对于std::cin
来说这是不可能的。您很容易使其引用无效的迭代器:
默认构造的
std::istream_iterator
称为流结束迭代器。当有效的std::istream_iterator
到达底层流的末尾时,它变成等于流结束迭代器。进一步解除引用或递增它会调用未定义的行为。
您的循环方式几乎可以了,不过我可能会使用更强的终止条件以避免对“无效”流进行多余读取:
vector<int> v(n);
for(vector<int>::size_type i = 0; i < n; i++)
if (!cin >> v[i])
break;
实际上,我很想将此封装为类似于std::copy_n
的东西,但接受完整的“范围”,其边界可以在从0到N计数的同时进行验证。
一个实现可能如下所示:
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;
}
你可以像这样使用它:
copy_atmost_n(
std::istream_iterator<int>(std::cin),
std::istream_iterator<int>(),
N,
std::back_inserter(v)
);
现在您获得了M个元素,其中M是提供的输入数量与N中较小的那个。
copy_n
的问题在于,如果在读取 n 个元素之前流遇到问题,则行为是未定义的?所以基本上,"如果你信任你的数据源,请去尝试,但如果你不信任,请不要使用 copy_n
"? - templatetypedefcopy_atmost_n
。 - Lightness Races in Orbit如评论所述,copy_n
在此任务中不安全,但您可以使用带有可变lambda的copy_if
:
#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;
}
正如这个答案所指出的:std::copy复制n个元素或到结尾
std::copy_n
不适合这个任务。 - Lightness Races in Orbitstd::istream_iterator
的“结束迭代器”进行解引用会导致未定义行为,而非抛出语义。(请参见我的答案) - Lightness Races in Orbitcopy_n
部分,只需保留_如评论中所述,copy_n 是不安全的,但您可以使用带有可变 lambda 的 copy_if:_ 然后跟随您的好解决方案。 - Ted Lyngmocopy_if
版本更好(已删除反对票)。从技术上讲,不能保证谓词将按顺序调用,但我们保证它将被调用 <last-first> 次,没有充分的理由以无序方式调用它。所以这应该可以工作。不过,像我的 copy_atmost_n
这样的包装器更简洁、更具表现力,更容易正确实现。 - Lightness Races in Orbit