使用istream_iterators构造向量

Adr*_*thy 13 c++ iterator stl vector

我记得曾经看到过使用迭代器将一个完整的二进制文件读入一个向量的巧妙方法.它看起来像这样:

#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;
}
Run Code Online (Sandbox Code Playgroud)

我们的想法是vector通过传递指定整个流的输入迭代器来使用's iterator范围构造函数.问题是我不确定要为最终迭代器传递什么.

你如何创建istream_iterator一个文件的结尾?我完全记错了这个成语吗?

wil*_*ell 26

你想要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>());
Run Code Online (Sandbox Code Playgroud)

编辑以满足C++最令人烦恼的解析.谢谢,@ UncleBens.

  • 谨防最令人烦恼的解析. (9认同)

pep*_*ico 6

在C++ 11中,我可以:

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

这个较短的形式避免了最令人烦恼的解析问题,因为{}参数消除了它作为参数或形式参数的歧义.

@ 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))),
        {}
    );
}
Run Code Online (Sandbox Code Playgroud)

  • @Stan 是的,它与 `std::istreambuf_iterator&lt;char&gt;()` 的作用相同,它是一个有用的构造,像 `auto` 一样工作,但是对于值(默认值)而不是单独的类型。 (2认同)