Построение вектора с помощью istream_iterators - PullRequest
12 голосов
/ 12 декабря 2010

Я помню, как однажды увидел умный способ использования итераторов для чтения всего двоичного файла в вектор. Выглядело это примерно так:

#include <fstream>
#include <ios>
#include <iostream>
#include <vector>

using namespace std;

int main() {
    ifstream source("myfile.dat", ios::in | ios::binary);
    vector<char> data(istream_iterator(source), ???);
    // do stuff with data
    return 0;
}

Идея состоит в том, чтобы использовать конструктор диапазона итератора vector, передавая входные итераторы, которые определяют весь поток. Проблема в том, что я не уверен, что передать конечному итератору.

Как создать istream_iterator для конца файла? Я совершенно не помню эту идиому?

Ответы [ 2 ]

25 голосов
/ 12 декабря 2010

Вы хотите std::istreambuf_iterator<>, для необработанного ввода.std::istream_iterator<> для форматированного ввода.Что касается конца файла, используйте конструктор потокового итератора по умолчанию.

std::ifstream source("myfile.dat", std::ios::binary);
std::vector<char> data((std::istreambuf_iterator<char>(source)),
                       std::istreambuf_iterator<char>());

Отредактировано для удовлетворения самого неприятного анализа C ++ .Спасибо, @ UncleBens.

6 голосов
/ 13 ноября 2015

В C ++ 11 можно:

std::ifstream source("myfile.dat", std::ios::binary);
std::vector<char> data(std::istreambuf_iterator<char>(source), {});

Эта более короткая форма позволяет избежать самой неприятной проблемы синтаксического анализа из-за аргумента {}, который устраняет двусмысленность, являющуюся аргументом или формальным параметром.

@ Ответ wilhelmtell также можно обновить, чтобы избежать этой проблемы, приняв инициализатор фигурной скобки для data. Тем не менее, на мой взгляд, использование {} более просто и не имеет значения для формы инициализации.

EDIT

Или, если бы у нас было std::lvalue (и, возможно, std::xvalue вместо std::move):

#include <vector>
#include <fstream>

template <typename T>
constexpr T &lvalue(T &&r) noexcept { return r; }

int main() {
    using namespace std;

    vector<char> data(
        istreambuf_iterator<char>(lvalue(ifstream("myfile.dat", ios::binary))),
        {}
    );
}
...