【问题标题】:Getting input directly into a vector in C++将输入直接输入到 C++ 中的向量中
【发布时间】:2011-05-09 22:37:28
【问题描述】:

考虑以下代码片段:

...
int N,var;
vector<int> nums;
cin >> N;
while (N--)
{
   cin >> var;
   nums.push_back(var);
}
...

是否可以在不使用辅助变量的情况下执行此操作,在本例中为 var

【问题讨论】:

  • 使用辅助变量有什么问题?你可以通过在循环中声明它来限制它的范围。
  • 并不是说辅助有什么问题,我只是好奇是否可以不使用辅助。
  • 请说清楚 - 您是否关心性能局部变量数代码行数 ?场景是否与您的商家信息完全相同,或者N 可能未知?
  • @Janusz,仅针对这种情况,即 N 是已知的。另外,我只对局部变量的数量感兴趣。

标签: c++ stl vector iostream


【解决方案1】:

假设您已经阅读了最初的N,使用istream_iterator 有一个很好的技巧:

std::vector<int> nums;
nums.reserve(N);
std::copy(std::istream_iterator<int>(std::cin), 
          std::istream_iterator<int>(),
          std::back_inserter(nums));

back_inserter 对象将自身变成一个迭代器,在最后将元素添加到向量中。迭代器流可以通过读取的元素类型进行参数化,如果没有给出参数,则表示输入结束。

【讨论】:

  • 这不是技巧,这就是istream_iterators 和输入迭代器概念的用途。
  • 为什么创建辅助back_inserter 对象而不是辅助int 更好? :D 仍然很好地使用了 STL。
  • 此代码不起作用。您使用默认值为 0 的 N 元素初始化向量,然后在 N 元素之外使用 push_back()
  • 可能是std::vector&lt;int&gt; nums; nums.reserve(N);
  • 如果没有给出 N:std::vector nums(std::istream_iterator(std::cin), std::istream_iterator());跨度>
【解决方案2】:

如果您的工具带中还没有copy_n(),那么您应该这样做。很有用。

template<class In, class Size, class Out>
Out copy_n(In first, In last, Size n, Out result)
{
    while( n-- > 0 && first != last )
        *result++ = *first++;
    return result;
}

使用这个实用程序可以方便而优雅地将 n 个元素复制到一个向量中:

#include<iterator>
#include<vector>
#include<iostream>

// ...
int n = 0;
std::cin >> n;
std::vector<int> v(n);
copy_n(std::istream_iterator<int>(std::cin), std::istream_iterator<int>(),
       n,
       v.begin());

【讨论】:

    【解决方案3】:
    vector<int> nums(N);
    for (int i = 0; i < N; i++)
    {
        cin >> nums[i];
    }
    

    在一般情况下,这实际上更有效。在没有初始 reserve 的情况下反复调用 std::vector::push_back() 会导致大量重新分配。

    【讨论】:

    • 实际上,operator[] 仍在检查范围滥用,因此将向量剥离为 C 指针并进行迭代会更有效:]
    • @Janusz:确实;但至少这永远不会调用resize
    • @Janusz:我认为operator[] 不会进行范围检查,但.at() 会?
    • @dreamlax,在 MSVC 实现中都检查范围,但你部分正确 - 如果 _HAS_ITERATOR_DEBUGGING 关闭,operator[] 不会
    • @dreamlax: operator[]保证进行范围检查,显然它是允许的,因为超出范围是 UB。如果它是在优化构建中进行范围检查,我认为您可能有理由向您的编译器供应商发送粗鲁的电子邮件。
    【解决方案4】:

    从 Diego Sevilla 的答案中得到暗示。 使用范围构造函数

    std::vector<int> nums( std::istream_iterator<int>(std::cin),
                           std::istream_iterator<int>() );
    

    【讨论】:

    • 如何停止输入?按Enter 不会完成输入。
    • @MilindR ENTER 后按 CTRL + D 停止输入。
    【解决方案5】:

    不需要分配向量然后调整它的大小。

    迭代器比索引更可取。

    size_t N;
    std::cin >> N;
    
    std::vector<int> values(N);
    for (vector<int>::iterator iter = values.begin(); iter != values.end(); ++iter)
    {
      std::cin >> *iter;
    }
    

    【讨论】:

      猜你喜欢
      • 2019-05-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多