Построение вектора с помощью итераторов istream

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

#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 ответов


вы хотите std::istreambuf_iterator<>, для сырья. The 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.


в C++11 можно:

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

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

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

редактировать

или, если мы 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))),
        {}
    );
}