Создать std :: stringbuf на основе std :: vector <char> - PullRequest
2 голосов
/ 26 марта 2012

Я делаю преобразования изображений в памяти между двумя фреймворками (OpenSceneGraph и wxWidgets). Не желая заботиться о базовых классах (osg::Image и wxImage), я использую функции ориентированного на поток ввода / вывода, которые оба API предоставляют следующим образом:

1) Создать std::stringstream

2) Записать в поток с использованием средств записи OSG

3) Чтение из потока с помощью считывателей wxWigdets

Это работает довольно хорошо. До сих пор я использовал прямой доступ к потоковому буферу, но недавно мое внимание привлекла проблема «несмежного базового буфера» std::stringstream. Я использовал kludge для получения const char* ptr в буфер - но он работал (проверено на Windows, Linux и OSX, с использованием MSVC 9 и GCC 4.x), поэтому я никогда не исправлял его.

Теперь я понимаю, что этот код - бомба замедленного действия, и я хочу от нее избавиться. Эта проблема поднималась несколько раз на SO ( здесь, например, ), но я не смог найти ответ, который действительно мог бы помочь мне сделать простейшую вещь, которая могла бы сработать.

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

1) требуемый размер не бесконечен и на самом деле вполне предсказуем

2) мой поток действительно должен быть std::iostream (я не могу использовать массив необработанных символов) из-за API

кто-нибудь знает, как я могу использовать пользовательский строковый буфер, используя вектор символов? Пожалуйста, не отвечайте «использовать std::stringstream::str()», так как я знаю, мы можем, но я точно ищу что-то другое (даже если бы вы сказали, что копирование 2-3 МБ происходит так быстро, что я даже не заметит разницы, давайте рассмотрим, что я все еще интересуюсь пользовательскими строковыми буферами только для красоты упражнения).

Ответы [ 2 ]

3 голосов
/ 26 марта 2012

Если вы можете использовать только istream или ostream (вместо двунаправленный), и не нужно искать, это довольно просто (около 10 строк кода), чтобы создать свой собственный streambuf, используя std::vector<char>. Но если строки очень, очень большие, зачем? Стандарт C ++ 11 гарантирует, что std::string является смежным; что char* полученный &myString[0] может использоваться в качестве массива стиля C. Причина, по которой C ++ 11 добавил эту гарантию, заключалась в признании существующих практика; просто не было никаких реализаций, где это не было случай (и теперь, когда это требуется, не будет никаких реализаций в будущее, где это не так).

1 голос
/ 26 марта 2012

boost :: iostreams имеет несколько готовых раковин для этого.Есть array_sink, если у вас есть какой-то верхний предел и вы можете выделить чанк заранее, такой прием не будет расти динамически, но с другой стороны, это также может быть положительным.Также есть back_inserter_device, который является более общим и работает, например, с std::vector.Пример использования back_inserter_device:

#include <string>
#include <iostream>
#include "boost/iostreams/stream_buffer.hpp"
#include "boost/iostreams/device/back_inserter.hpp"
int main() 
{
    std::string destination;
    destination.reserve( 1024 ); 
    boost::iostreams::stream_buffer< boost::iostreams::back_insert_device< std::string > > outBuff( ( destination ) );
    std::streambuf* cur = std::cout.rdbuf( &outBuff );
    std::cout << "Hello!" << std::endl;
    // If we used array_sink we'd need to use tellp here to retrieve how much we've actually written, and don't forgot to flush if you don't end with an endl!
    std::cout.rdbuf( cur );
    std::cout << destination;
}
...