# Creating an istream peeker

I want an istream that you can safely peek arbitrarily many characters from. This works as far as I can tell, but I am unsure if this is really "the right way" to do it since the iostream library is pretty cryptic to me.

class peekbuf : public std::streambuf
{
std::streambuf* sbuf_;
std::vector<char> data_;
char ch;
public:
peekbuf(std::streambuf* s)
: sbuf_(s)
{ }

std::vector<char> const& peek(int N) {
data_.clear();
data_.reserve(N);
for (int i = 0; i < N; ++i) {
int next = sbuf_->sbumpc();
if (next == traits_type::eof()) {
break;
}
data_.push_back(next);
}

if (!data_.empty()) {
setg(data_.data(), data_.data(), data_.data() + data_.size());
}

return data_;
}

protected:
int_type underflow() override {
ch = sbuf_->sbumpc();
setg(&ch, &ch, &ch + 1);
return ch;
}
};


Example usage:

int main() {
peekbuf buf{std::cin.rdbuf()};
std::cin.rdbuf(&buf);

auto first5 = buf.peek(5);

std::string s;
std::cin >> s;
std::cout << "Got " << s << '\n';

std::cout << "Peeked: ";
for (char c : first5) {
std::cout << c;
}
std::cout << '\n';
}


Where:

\$ echo 123456789 | ./a.out


yields:

Got 123456789
Peeked: 12345

• I don;t have time write now (this weekend). But something feels wrong. When you set the underlying buffer with setg(data_.data(), data_.data(), data_.data() + data_.size()); I would expect you to save the state of the current buffer so when you have finished reading your peeked data you can go back to the original buffer. – Martin York May 5 '16 at 17:33