The istream
is a reference of raw data. It doesn't hold the data, and just a visitor, by keeping some char*
pointers of the begin and end of data memory address.
The storage in vector<> is continuous, but by using push_back()
, the storage address may changed, (copied inner vector)
So it's possible to make an istream
to const vector
The reference
https://en.cppreference.com/w/cpp/io/basic_istream
https://www.cplusplus.com/reference/streambuf/streambuf/
The shortest example
class vectorbuf : public std::streambuf {
public:
vectorbuf(std::vector<uint8_t> &v){
setg((char*)v.data(), (char*)v.data(), (char*)(v.data() + v.size()));
}
~vectorbuf() {}
};
//Usage:
vector<uint8_t> arr{11,12,13,14,15,16};
vectorbuf vbuf(arr);
std::istream is(&vbuf);
The full WRONG sample code
#include <streambuf>
#include <iostream>
#include <iomanip>
#include <vector>
using namespace std;
template<typename T>
class vectorbuf : public std::streambuf {
public:
vectorbuf(std::vector<T> &v) : _value(v) {
char *bptr = (char*)_value.data();
char *eptr = (char*)(_value.data() + _value.size());
setg(bptr, bptr, eptr);
cout<<"Setg: "<<(void*)bptr<<" "<<(void*)eptr<<endl;
}
~vectorbuf() {}
//Zone start ---
//Note: this zone of code can be commented since the virtual function in base class do same
protected:
virtual int underflow() {
char *bptr = (char*)_value.data();
char *new_eptr = (char*)(_value.data() + _value.size());
cout<<"[underflow() when gptr()="<<(void*)gptr()
<<", now_bptr="<<(void*)bptr<<" now_eptr="<<(void*)new_eptr<<"]";
return traits_type::eof();
//since the vector& must not modified, the code below is unnecessary.
if (new_eptr == egptr())
return traits_type::eof();
setg(bptr, gptr(), new_eptr);
return *gptr();
}
//Zone end ---
private:
std::vector<T> &_value;
};
int main() {
vector<int> arr{'a',12,13,14,15};
cout<<"The array: ";
for (int i=0; i<arr.size(); i++)
cout<<arr[i]<<" ";
cout<<endl;
cout<<" storage: ";
for (int i=0; i<arr.size()*sizeof(int); i++) {
char *ptr = (char*)arr.data();
cout<<static_cast<int>(ptr[i])<<" ";
}
cout<<endl;
vectorbuf<int> vbuf(arr);
std::istream is(&vbuf);
arr.push_back(16); //!!! wrong code here !!!
//the size of arr is 6*4 == 24, with sizeof(int)==4
for (int i=0; i<26; i++) {
cout<<"good?"<<is.good()
<<", fail?"<<is.fail()
<<", bad?"<<is.bad()
<<", eof?"<<is.eof()
<<", tellg="<<is.tellg();
//Note there must be char
//'int a' would not accepted and make is.fail() to true
//and std::noskipws is also importanted
char a;
is>>std::noskipws>>a;
int out = a;
cout<<", Read from arr: "<<out<<endl;
}
return 0;
}