2009-09-19 3 views
12

У меня есть блок памяти (непрозрачный), который я хочу сохранить в Blob в mySQL через их C++-адаптер. Адаптер ожидает IStream:инициализация C++ std :: istringstream из буфера памяти?

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

Так что мой вопрос: как я могу создать зЬй :: IStream из этого блока памяти (классифицирован как символ *). Это не строка, поскольку она не завершена нулевым (но я знаю ее длину).

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

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

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

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

Это правильный путь?

+0

Возможный дубликат [Установка внутреннего буфера, используемого в стандартном потоке (pubsetbuf)] (http://stackoverflow.com/questions/1494182/setting-the-internal-buffer- used-by-a-standard-stream-pubsetbuf) –

ответ

7

Посмотрите на станд :: istrstream имеет конструктор

istrstream(char* pch, int nLength); 

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

+5

Да, но Josuttis говорит, что «классы потока char * сохраняются только для обратной совместимости. Их интерфейс подвержен ошибкам, и они редко используются правильно». Вот почему я немного неохотно использовал их. И «сохраненный только для обратной совместимости», по-видимому, подразумевает, что существует лучший способ использования «лучших» классов. –

+0

Я прочитал эту статью, это прямо актуально. Благодарю. Думаю, на мой вопрос ответил, хотя и не комментирует «tmp_blob.rdbuf() -> pubsetbuf (blockPtr, blockLength); "подход. –

6

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

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

0

UNTESTED но, возможно, стоит тест ...

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

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

37

На самом деле довольно тривиально написать одноразовый файл 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(); 
} 
+0

Ха-ха, ваше решение не появилось в результатах поиска, когда я разместил свой вопрос. У нас есть почти то же самое;) http: // stackoverflow .com/вопросы/2079912/проще-полосная-к-создать-Ac-MemoryStream-из-полукокса-sizet-без-копировальные-го –

Смежные вопросы