Получить истрику от персонажа * - PullRequest
51 голосов
/ 16 октября 2011

У меня есть char * и длина данных, которые я получаю из библиотеки, и мне нужно передать данные в функцию, которая принимает istream.

Я знаю, что могу создать поток строк, ноэто скопирует все данные.Кроме того, данные, безусловно, будут иметь значения 0, поскольку это zip-файл, и при создании потока строки данные будут приниматься до первого 0, я думаю.

Есть ли способ создать istream из char *, и эторазмер без копирования всех данных?

Ответы [ 6 ]

65 голосов
/ 16 октября 2011

Вот не устаревший метод , найденный в сети , у вас есть собственный класс std::streambuf, но он прост и, кажется, работает:

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

struct membuf : std::streambuf
{
    membuf(char* begin, char* end) {
        this->setg(begin, begin, end);
    }
};

int main()
{
    char buffer[] = "I'm a buffer with embedded nulls\0and line\n feeds";

    membuf sbuf(buffer, buffer + sizeof(buffer));
    std::istream in(&sbuf);
    std::string line;
    while (std::getline(in, line)) {
        std::cout << "line: " << line << "\n";
    }
    return 0;
}

Какие выходные данные:

line: I'm a buffer with embedded nullsand line
line:  feeds
12 голосов
/ 29 сентября 2012

Не устарелое решение с использованием Boost:

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

basic_array_source<char> input_source(my_ptr_to_char, byte_count);
stream<basic_array_source<char> > input_stream(input_source);

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

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

bufferstream input_stream(my_ptr_to_char, byte_count);
6 голосов
/ 23 июля 2015

Мне нужно решение, которое поддерживает tellg и seekg и не требует повышения.

char_array_buffer из Руководство для начинающих по написанию пользовательского буфера потока (std :: streambuf) дал полученную начальную точку.

byte_array_buffer.h:

#include <cstdio>
#include <string>
#include <list>
#include <fstream>
#include <iostream>

//
// http://www.mr-edd.co.uk/blog/beginners_guide_streambuf
//

class byte_array_buffer : public std::streambuf
{
public:
    byte_array_buffer(const uint8_t *begin, const size_t size);

private:
    int_type underflow();
    int_type uflow();
    int_type pbackfail(int_type ch);
    std::streamsize showmanyc();
    std::streampos seekoff ( std::streamoff off, std::ios_base::seekdir way,
                            std::ios_base::openmode which = std::ios_base::in | std::ios_base::out );
    std::streampos seekpos ( std::streampos sp,
                            std::ios_base::openmode which = std::ios_base::in | std::ios_base::out);

    // copy ctor and assignment not implemented;
    // copying not allowed
    byte_array_buffer(const byte_array_buffer &);
    byte_array_buffer &operator= (const byte_array_buffer &);

private:
    const uint8_t * const begin_;
    const uint8_t * const end_;
    const uint8_t * current_;
};

byte_array_buffer.cpp:

#include "byte_array_buffer.h"

#include <cassert>


byte_array_buffer::byte_array_buffer(const uint8_t *begin, const size_t size) :
begin_(begin),
end_(begin + size),
current_(begin_)
{
    assert(std::less_equal<const uint8_t *>()(begin_, end_));
}

byte_array_buffer::int_type byte_array_buffer::underflow()
{
    if (current_ == end_)
        return traits_type::eof();

    return traits_type::to_int_type(*current_);
}

byte_array_buffer::int_type byte_array_buffer::uflow()
{
    if (current_ == end_)
        return traits_type::eof();

    return traits_type::to_int_type(*current_++);
}

byte_array_buffer::int_type byte_array_buffer::pbackfail(int_type ch)
{
    if (current_ == begin_ || (ch != traits_type::eof() && ch != current_[-1]))
        return traits_type::eof();

    return traits_type::to_int_type(*--current_);
}

std::streamsize byte_array_buffer::showmanyc()
{
    assert(std::less_equal<const uint8_t *>()(current_, end_));
    return end_ - current_;
}


std::streampos byte_array_buffer::seekoff ( std::streamoff off, std::ios_base::seekdir way,
                                           std::ios_base::openmode which )
{
    if (way == std::ios_base::beg)
    {
        current_ = begin_ + off;
    }
    else if (way == std::ios_base::cur)
    {
        current_ += off;
    }
    else if (way == std::ios_base::end)
    {
        current_ = end_;
    }

    if (current_ < begin_ || current_ > end_)
        return -1;


    return current_ - begin_;
}

std::streampos byte_array_buffer::seekpos ( std::streampos sp,
                                           std::ios_base::openmode which )
{
    current_ = begin_ + sp;

    if (current_ < begin_ || current_ > end_)
        return -1;

    return current_ - begin_;
}
5 голосов
/ 16 октября 2011

Единственный (простой) переносимый способ включает изготовление копии:

std::istringstream ss(std::string(buf,len));

На самом деле, это скорее всего копирование данных дважды, один раз для создания string и один раз для создания istringstream. (Возможно, C ++ 11 может избежать одной из копий с помощью конструктора перемещения; я не уверен.)

Однако, если вам повезет, ваша реализация C ++ позволит вам сделать это:

std::istringstream ss;
ss.rdbuf()->pubsetbuf(buf,len);

В GNU C ++ (и, я полагаю, в некоторых других реализациях) это создаст поток строк без копирования данных. Но это поведение, определяемое реализацией в соответствии со спецификацией. (См. Также этот вопрос .)

Включая параметр len, вы гарантируете, что у обоих из них не будет проблем с нулевыми символами.

Единственный переносимый способ сделать то, что вы хотите, - реализовать собственный подкласс stringbuf и использовать его для инициализации потока строк. Не для слабонервных.

1 голос
/ 16 октября 2011

Вы пробовали std :: istrstream?http://stdcxx.apache.org/doc/stdlibref/istrstream.html

Технически, я думаю, что это устарело, но все еще является частью стандарта.

0 голосов
/ 16 октября 2011

Попробуйте исходные и приемные классы массива Boost.Iostreams.

http://www.boost.org/doc/libs/1_47_0/libs/iostreams/doc/index.html

...