Инициализация С++ std:: istringstream из буфера памяти?

У меня есть блок памяти (непрозрачный), который я хочу сохранить в Blob в mySQL через их С++-адаптер. Адаптер ожидает istream:

virtual void setBlob(unsigned int parameterIndex, std::istream * blob) = 0;

Итак, мой вопрос: как я могу создать std:: istream из этого блока памяти (напечатано как char *). Это не строка, поскольку она не заканчивается на нуль (но я знаю ее длину, конечно).

Я не мог найти способ сделать это, не копируя блок памяти, например, в std::string. Я думаю, что это немного расточительно. Что-то вроде этого не работает:

    std::streambuf istringbuf(blockPtr, blockLength);
    std::istringstream tmp_blob(&istringbuf);

потому что std:: streambuf не имеет такого конструктора. Я видел следующее предложение.

    std:: istringstream       tmp_blob;
    tmp_blob.rdbuf()->pubsetbuf(blockPtr, blockLength);

Правильно ли это?

Ответы

Ответ 1

Посмотрите на std:: istrstream, у него есть конструктор

 istrstream( char* pch, int nLength );

Этот класс как бы обесценился или, по крайней мере, вам обычно говорят использовать другие классы.
Проблема с strstream заключается в том, что сложнее управлять памятью буфера char *, поэтому, в общем, вы предпочтете stringstream, так как это управление памятью для вас. Однако в этом случае вы уже управляете памятью char *, поэтому обычная выгода в этом случае стоит. Фактически в этом случае strstream делает именно то, что вы хотите, с минимальными накладными расходами в коде или скорости. Это похоже на обсуждение ostrsteram by Herb Sutter

Ответ 2

На самом деле довольно тривиально писать одноразовый std::streambuf, который использует буфер на месте, поскольку поведение по умолчанию для всех виртуальных функций std::streambuf делает "правильная вещь". Вы можете просто setg область чтения в конструкции, а underflow и uflow можно смело оставить для возврата traits_type::eof(), так как конец начальной области получения - это конец потока.

например:.

#include <streambuf>
#include <iostream>
#include <istream>
#include <ostream>

struct OneShotReadBuf : public std::streambuf
{
    OneShotReadBuf(char* s, std::size_t n)
    {
        setg(s, s, s + n);
    }
};

char hw[] = "Hello, World!\n";

int main()
{
    // In this case disregard the null terminator
    OneShotReadBuf osrb(hw, sizeof hw - 1);
    std::istream istr(&osrb);

    istr >> std::cout.rdbuf();
}

Ответ 3

Boost.IOStreams имеет поток, который работает как stringstream, но обертывает собственный массив, поэтому вам не нужно копировать данные.

std:: stringstream всегда создает свой собственный внутренний буфер

Ответ 4

Неподтвержденный, но, возможно, стоит тест...

std::stringstream ss;
ss.write( blockPtr, blockLength );
ss.seekg(0);

Затем вызовите эту функцию setBlob с помощью ss. У вас все еще есть внутренний буфер в std:: stringstream, как уже упоминалось.