【问题标题】:copy_n or until eof?copy_n 还是直到 eof?
【发布时间】:2011-12-04 23:32:09
【问题描述】:

我将如何使用 STL 算法做到这一点?

std::ifstream file(filename);

std::vector<unsigned char> buf;
for(auto file_it = std::istreambuf_iterator<char>(file); file_it != std::istreambuf_iterator<char>() && buf.size() < 2048; ++file_it)
    buf.push_back(*file_it);

注意buf.size() &lt; 2048

例如如果我执行以下操作,并且文件小于 2048 字节,会发生什么情况?

std::copy_n(std::istreambuf_iterator<char>(file), 2048, std::back_inserter(buf));

【问题讨论】:

  • 如果文件变大了怎么办?其余部分是否被丢弃,或者您是否需要一个迭代器来开始仍待读取的部分?
  • 一旦读取了所需的字节数,ifstream 就会被丢弃。
  • 这开启了使用单独的迭代器而不是算法的可能性。

标签: c++ algorithm file


【解决方案1】:

就像文档说的那样,std::copy_n()完全复制 n 项目。它将继续读取迭代器引用的序列的末尾。不过,我不确定标准对istreambuf_iterator&lt;&gt; 的规定。这可能是未定义的行为,但流可能会在末尾生成大量 eof() 的副本。当可用字节少于2048 时,这可能会导致大量垃圾。

无论如何,如果您想可靠地复制 n 个项目,您需要编写自己的函数:

template<typename I1, typename I2, typename size_type>
I copy_upto_n ( I1 begin, I1 end, size_type n, I2 out )
{
    for (size_type i=0; (i < n) && (begin != end); ++i)
    {
        *out++ = *begin++;
    }
    return out;
}

有些人可能会使用std::iterator_traits&lt;&gt; 而不是额外的模板参数来强制使用与迭代器相同的距离类型。

【讨论】:

  • +1 用于通用迭代器算法和std::iterator_traits的提及。
  • out 应该是一个单独的模板参数。
  • @pmr:确实。没有它,它不适用于问题中发布的用例(例如使用std::back_inserter())。我将编辑代码。
  • @ChristianRau:现在我想到了,使用迭代器特征是没有必要的。就像std::copy_n() 一样,整数类型应该有一个额外的模板参数。那么i可以代表[0,n)中的所有值。
  • @AndréCaron 是的,甚至更好,因为它并没有真正用作迭代器距离,而是一个独立的计数器。
【解决方案2】:

您可以使用特殊的back_insert_iterator 来丢弃基于谓词的操作。

此代码已无耻地取自 GCC 实现 标准库并进行了改编。 C++03 版本应该只需要一个 Container::const_reference 在作业中。

template<typename Container, typename Predicate>
class discarding_back_inserter
  : public iterator<output_iterator_tag, void, void, void, void>
{
  Container* container;
  Predicate p;
public:
  typedef Container          container_type;

  explicit
  back_insert_iterator(Container& x, Predicate p) : container(&__x), p(p) { }

  back_insert_iterator&
  operator=(const typename Container::value_type& value)
    {
      if(*container) 
        container->push_back(__value);
      return *this;
    }

  back_insert_iterator&
  operator=(typename _Container::value_type&& value)
    {
      if(*container) 
        container->push_back(std::move(__value));
      return *this;
    }

  back_insert_iterator&
  operator*()
    { return *this; }

  back_insert_iterator&
  operator++()
    { return *this; }

  back_insert_iterator
  operator++(int)
    { return *this; }
};

【讨论】:

  • 不要把这个当作个人的,但是,eww。
  • @BenjaminLindley Nah,从来没有。我只是认为值得寻找相反的方法来修改算法。结果甚至不是很通用,因为它适用于容器。我真的很想有一个基于Maybe 值的generate 版本。这将使这变得非常容易。
  • 这根本不使用谓词。如果谓词存储了指向流的指针,它可能会起作用,以便它可以检查 eof。 value 参数不会提供太多信息。
  • @UncleBens 啊,对。我忘了应该是if(p(*container))
猜你喜欢
  • 2014-12-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-10-18
  • 2013-01-10
  • 1970-01-01
相关资源
最近更新 更多