Инициализация С++ 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, как уже упоминалось.