copy_n или до eof? - PullRequest
       4

copy_n или до eof?

7 голосов
/ 05 декабря 2011

Как бы я сделал это, используя алгоритмы 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() < 2048.

например, что произойдет, если я сделаю следующее, а размер файла будет меньше 2048 байт?

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

Ответы [ 2 ]

1 голос
/ 05 декабря 2011

Как сказано в документации, std::copy_n() скопирует точно n элементов. Он будет продолжать читать после конца последовательности, на которую ссылается итератор. Я не уверен, что стандарт говорит о istreambuf_iterator<>, хотя. Это, вероятно, неопределенное поведение, но потоки, вероятно, произведут много копий 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<> вместо дополнительного параметра шаблона, чтобы принудительно использовать тот же тип расстояния, что и итератор.

0 голосов
/ 05 декабря 2011

Вы можете использовать специальный back_insert_iterator, который отбрасывает операции на основе предиката.

Этот код был бесстыдно взят из реализации GCC stdlib и адаптирован Версия 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; }
};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...