2012-01-11 9 views
21

chcę owijać vector<char> z std::istream (tak przeczytaniu wektor będzie odbywać się za pośrednictwem interfejsu istream)C++: owijarki wektor <char> z istream

Jaki jest sposób to zrobić?

+0

To nie do końca jasne, co chcesz robić. Czy możesz podać przykład kodu, który chciałbyś móc napisać? –

+0

Używam biblioteki, która oczekuje, że istream zużyje. Ale mam tylko wektor pod ręką, dlatego muszę go jakoś opakować. – GabiMe

+0

Czy to wystarczy: http://stackoverflow.com/questions/4991697/wraps-a-vectorunsigned-char-inside-a-stream –

Odpowiedz

27

Można by zdefiniować streambuf podklasę owijając vector i przekazać instancję że do konstruktora istream.

Jeśli dane nie ulegną zmianie po zakończeniu budowy, wystarczy ustawić wskaźniki danych za pomocą streambuf::setg(); wdrożenie domyślne dla pozostałych członków robi słusznie:

template<typename CharT, typename TraitsT = std::char_traits<CharT> > 
class vectorwrapbuf : public std::basic_streambuf<CharT, TraitsT> { 
public: 
    vectorwrapbuf(std::vector<CharT> &vec) { 
     setg(vec.data(), vec.data(), vec.data() + vec.size()); 
    } 
}; 

std::vector<char> data; 
// ... 
vectorwrapbuf<char> databuf(data) 
std::istream is(&databuf); 

Jeśli potrzebujesz czegoś bardziej zaawansowanego niż, zastąpić metodę streambuf::underflow.

+0

Dzięki. czy brzydkie & * vec.begin() można zastąpić vec.data()? – GabiMe

+0

Oczywiście, tak samo jak '& * vec.end()' można zastąpić 'vec.data() + vec.size()'. –

+1

Uwaga: 'std :: istream' nie zwalnia wskaźnika. Lepiej utwórz streiabuffer na stosie. – ybungalobill

2

Można by mógł po prostu uciec z budynku klasy, która implementuje >> operatora jak strumień, coś takiego:

template<class _ITy> 
class RangeStreamLite 
{ 
private: 

    _ITy Begin; 
    _ITy End; 
    _ITy Next; 

public: 

    RangeStreamLite(_ITy begin, _ITy end) : 
     Begin(begin), 
     End(end), 
     Next(begin) 
    { 
     // Do nothing. 
    } 

    template<class _OTy> 
    RangeStreamLite& operator>>(_OTy& out) 
    { 
     out = *Next; 
     ++Next; 
     return *this; 
    } 


    void reset() 
    { 
     Next = Begin; 
    } 
}; 

Jest to rozwiązanie 'quick and dirty', A „lite stream ", nie jest to właściwie strumień we właściwym znaczeniu, ale działa, gdy wszystko, czego potrzebujesz, jest powierzchownym urządzeniem podobnym do strumienia. Prawidłowe utworzenie strumienia niestandardowego jest nieco bardziej skomplikowane i wymagałoby dziedziczenia ze std :: streambuf i implementowania niezbędnych funkcji. Oto kilka linków warte obejrzenia:

-1

Będziesz musiał napisać niestandardową implementację strumienia, która dziedziczy po istream. Można to łatwo zrobić za pomocą Boost.Iostreams - wszystko, co musisz zrobić, to zaimplementować prosty Source.

+1

Dowolne, ponieważ pośrednie/łączenie z rozwiązaniami zamiast dostarczania ich jest sprzeczne z koncepcją przepełnienia stosu. – Catskul

5

Dostosowanie odpowiedź od Get an istream from a char* i przyjmując to, co próbujesz zrobić:

// Forward declarations 
std::vector<char> my_create_buffer(); 
void my_consume_buffer(std::istream & is); 

// What you want to be able to write 
std::vector<char> buffer = my_create_buffer(); 
my_consume_buffer(wrap_vector_as_istream(buffer)); 

Następnie można utworzyć wrap_vector_as_istream tak (choć niesprawdzone):

#include <iostream> 
#include <istream> 
#include <streambuf> 
#include <string> 

struct wrap_vector_as_istream : std::streambuf 
{ 
    wrap_vector_as_istream(std::vector<char> & vec) { 
     this->setg(&vec[0], &vec[0], &vec[0]+vec.size()); 
    } 
}; 

jedna rzecz być jednak świadomym. Obiekt, który utworzyłeś, zawiera wskaźniki do pamięci wektorów. Więc jeśli dodasz lub usuniesz wartości do wektora, podczas gdy ta owijka się unosi, nastąpi awaria.

(Oh i jeśli się głosować mi, proszę się głosować post mam z tego przystosowany.)

10

użyciu doładowania:

#include <boost/iostreams/stream.hpp> 
#include <boost/iostreams/device/array.hpp> 
using namespace boost::iostreams; 

basic_array_source<char> input_source(&my_vector[0], my_vector.size()); 
stream<basic_array_source<char> > input_stream(input_source); 

lub jeszcze prościej:

#include <boost/interprocess/streams/bufferstream.hpp> 
using namespace boost::interprocess; 

bufferstream input_stream(&my_vector[0], my_vector.size()); 
0

Jeśli masz problemy z zamianą swojego vector<char>, możesz użyć Boost Interprocess' vectorstream.Przykład:

#include <boost/interprocess/streams/vectorstream.hpp> 

#include <vector> 
#include <string> 
#include <iostream> 


using namespace std; 

int main(int argc, char **argv) 
{ 
    static const char inp[] = "123 45 666"; 
    vector<char> v(inp, inp + sizeof inp - 1); 
    using ivectorstream = 
    boost::interprocess::basic_ivectorstream<std::vector<char>>; 
    ivectorstream is; 
    is.swap_vector(v); 
    while (!is.eof()) { 
    int i = 0; 
    is >> i; 
    cout << i << '\n'; 
    } 
    is.swap_vector(v); 
    cout << string(v.begin(), v.end()) << '\n'; 
    return 0; 
} 

Ewentualnie, jeśli nie mogą lub nie chcą zmutować swoje vector<char>, można użyć Boost Interprocess' bufferstream. Z bufferstream, nie musisz zamieniać swojego wektora na to. Przykład:

#include <boost/interprocess/streams/bufferstream.hpp> 

#include <vector> 
#include <string> 
#include <iostream> 


using namespace std; 

int main(int argc, char **argv) 
{ 
    static const char inp[] = "123 45 666"; 
    vector<char> v(inp, inp + sizeof inp - 1); 
    boost::interprocess::ibufferstream is(v.data(), v.size()); 
    while (!is.eof()) { 
    int i = 0; 
    is >> i; 
    cout << i << '\n'; 
    } 
    return 0; 
}