Подтвердить что ты не робот

С++: вектор обтекания <char> с istream

Я хочу обернуть vector<char> с помощью std::istream (поэтому чтение вектора будет выполняться через интерфейс istream)

Каким образом это сделать?

4b9b3361

Ответ 1

Вы должны определить подкласс streambuf, обертывающий vector, и передать экземпляр этого в конструктор istream.

Если данные не изменяются после построения, достаточно настроить указатели данных с помощью streambuf::setg(); реализация по умолчанию для других участников делает правильную вещь:

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);

Если вам нужно что-то более продвинутое, переопределите метод streambuf::underflow.

Ответ 2

с использованием Boost:

#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);

или даже проще:

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

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

Ответ 3

Адаптация ответа от Получите istream от char * и предположим, что это то, что вы пытаетесь сделать:

// 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) );

Затем вы можете создать wrap_vector_as_istream следующим образом (непроверенный):

#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() );
    }
};

Одна вещь, о которой нужно знать. Созданный объект содержит указатели на память векторов. Поэтому, если вы добавляете или удаляете значения в вектор, имея вокруг этого обертки, вы направляетесь к сбою.

(О, и если вы меня проголосуете, пожалуйста, голосуйте за сообщение, которое я адаптировал.)

Ответ 4

Вам бы удалось просто создать класс, который реализует оператор → как поток, что-то вроде этого:

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;
    }
};

Это "быстрое и грязное" решение, "поток lite", это не поток в правильном смысле, но он работает, когда все, что вам нужно, является поверхностным потоковым устройством. Правильное создание пользовательского потока немного сложнее и потребует от вас наследования из std:: streambuf и реализации необходимых функций. Вот несколько ссылок, которые стоит посмотреть:

Ответ 5

Если вам хорошо сменить ваш vector<char>, вы можете использовать Boost Interprocess 'vectorstream. Пример:

#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;
}

В качестве альтернативы, если вы не можете или не хотите мутировать ваш vector<char>, вы можете использовать Boost Interprocess 'bufferstream. С bufferstream вам не нужно менять свой вектор. Пример:

#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;
}

Ответ 6

Вам нужно будет написать настраиваемую поточную реализацию, которая наследует от istream. Это легко сделать с помощью Boost.Iostreams - все, что вам нужно сделать, это реализовать простой Source.