| Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
| Форум программистов > C/C++: Общие вопросы > memory stream в C++ |
| Автор: Superklug 18.6.2010, 09:36 | ||
| Доброго времени суток! Существуют ли в C++ средства для работы с памятью как с потоком? Есть класс, для которого есть возможность сериализации. В поток записываются бинарные данные. Если нужно записать объект в память, то в качестве потока использую std::stringstream, затем преобразование вида:
А вот с десериализацией возникла проблема( Есть void*, а как с ним работать как с потоком - не знаю. Если бы был известен размер, можно было бы просто скопировать в stringstream, но размера я не знаю. Пока две мысли: написать копии функций для сериализации/десериализации только не для потоков, а для void*. Либо создать свой класс потока (унаследоать от стандартного потока stl). Ни тот, ни другой вариант не нравится( Надеюсь на вашу помощь.. Заранее спасибо! |
| Автор: azesmcar 18.6.2010, 09:42 |
| измени сериализацию и пиши размер в первые 2/4 байта бинарных данных. |
| Автор: Superklug 18.6.2010, 11:10 |
| azesmcar, возможности писать размер - нет. Формат бинарных данных определен строго... А что значит измени сериализацию? |
| Автор: Superklug 18.6.2010, 11:16 | ||
Разумеется там указывается размер. Просто это не размер всего блока данных. Например массив из двух строк: первый размер - 2, а затем еще для каждой строки. ( 2 6"привет" 5"hello"). Ну это очень грубо говоря) Вобщем оценить размер всего блока данных достаточно сложно... Хотелось бы читать данные из памяти как из потока... |
| Автор: Superklug 18.6.2010, 11:18 |
Я бы рад) Да вот только не знаю как... Как перевести из void* в stringstream не зная размера? Добавлено через 1 минуту и 40 секунд Earnest, прошу прощения.. Не правильно прочитал. Сейчас разберусь с strstream.. На первый взгляд - то, что нужно! Спасибо! |
| Автор: Earnest 18.6.2010, 11:20 |
| Да, не заметила, что ты не знаешь размер буфера... Нехорошо, присоединяюсь к предыдущему оратору: измени код так, чтобы знать. Ведь откуда-то ты этот буфер берешь, не с неба же. |
| Автор: azesmcar 18.6.2010, 11:22 |
читай как хочешь, но в конечном итоге это чтение из бинарного блока данных, и если о его размере ничего не известно то никакой адаптер в виде потоков не поможет. кстати это не меняет формата данных, будешь считать, что твои данные начинаются по смещению 2 байта, а первые 2 будешь использовать для хранения размера. |
| Автор: Superklug 18.6.2010, 11:26 | ||
=) Сейчас поясню подробней... Есть класс который представляет собой что-то похожее на Variant. Его упаковывают в особый бинарный формат. Разумеется когда упаковали размер известен. Эти упакованные данные передаются в функции DLL как const void*. Можно конечно в эти же функции передавать и размер (отдельным параметром), но хочется обойтись без этого. Формат же содержит размер, хоть и не явно. Если бы была возможность работать с памятью, как с потоком, то никаких проблем не было бы. Т.е. последовательно читать байты из памяти и все... Можно (наверное) написать наследника от istream и определить нужные операции. Но это решение кажется каким-то громоздким. Вот и подумал, что существует способ получше. |
| Автор: azesmcar 18.6.2010, 11:28 | ||
повторяюсь, это сводится к чтению того же бинарного блока данных, то, что ты хочешь - обыкновенный адаптер, в конечном итоге этот код чтения должен быть где-то написан, а как его писать, если ты размера не знаешь. |
| Автор: Superklug 18.6.2010, 11:36 |
| Не понимаю =( Рассмотрю пример, приведенный выше... Есть void*. Считываю первые 4 байта (int) - получаю количество элементов массива (2шт). Затем считываю еще 4 байта - получаю число символов в строке. Затем считываю соответствующее число байт для строки. После этого так же считываю вторую строку. Все корректно считается не смотря на то, что суммарного размера (23 байта) я не знал. |
| Автор: azesmcar 18.6.2010, 11:39 | ||||
Superklug
и сколько так? как узнать, что пора остановиться? Ты же сам писал, что тебе нужен размер всего блока и это бы решило проблему.
ну так добавь размер, в чем проблема? |
| Автор: Superklug 18.6.2010, 11:45 |
Все просто.. Первый элемент - число элементов массива. Как только считал столько элементов, так и останавливаешься. К слову там не обязательно массивы и строки. Это пример просто иллюстрирует принцип. |
| Автор: azesmcar 18.6.2010, 11:48 | ||
уже что-то, хоть это известно а элементы массива разных размеров? |
| Автор: Superklug 18.6.2010, 11:52 | ||
Еще раз повторяюсь. Размер косвенно известен. Т.е. вовремя остановиться - не проблема. Там самые разные типы... Строки, числа, массивы, объекты, бинарные данные. Структуры могут быть вложены (например массив массивов). Но все размеры известны, все можно корректно считать. Просто средство для считывания (десериализации) работает с потоками... |
| Автор: Earnest 18.6.2010, 12:42 |
| Superklug, понятно, что если разбирать буфер ручками, то конец найти можно. Но это лишает тебя возможности использовать стандартные потоки. Можно написать свой вариант потока, который будет отслеживать конец, конечно. Но поток тогда будет сильно проприетарный - только для одного формата. Неудобно, короче. Дополнительный параметр - размер буфера очень сильно облегчит дело. Так что я бы переписала (добавив, как уже предлагалось, в начало размер) или как-то по-другому передав размер. В strstream тогда это запихивается элементарно: кажется там есть конструктор с адресом и размером. При записи я бы тоже использовала strstream, ибо доставать c_str из string некузяво: а вдруг там 0 где-нибудь? Понятно, что и размер добыть можно, но лучше уж буфер. |
| Автор: Superklug 18.6.2010, 12:42 |
| Наверняка подобное уже писали. Что-то типа memory stream как наследник от стандартного потока stl. Может в boost::iostreams есть? |
| Автор: Earnest 18.6.2010, 12:47 |
| Ну сам подумай: откуда, не зная размера буфера, этот гипотетический поток узнает где конец? У клиента спрашивать будет? Можешь, конечно, порыться в strstream и посмотреть как он конец отслеживает, может там что-то можно кастомизировать. Но ей-богу, неправильно это. По соотношению "сложность реализации"\"полезность" вариант с добычей размера несомненно зашкаливает в положительном смысле. |
| Автор: azesmcar 18.6.2010, 12:49 | ||
| Superklug Я не про это, я ищу возможность посчитать полный размер блока без итерации, не пойму в чем проблема хранить полный размер? Зачем искусственно создавать себе проблемы? Добавлено через 53 секунды
и по твоему это легче, чем просто добавить размер в начало буфера? |
| Автор: Superklug 18.6.2010, 12:51 | ||||
Доверюсь вашему авторитетному мнению... Копаться в stl гиблое дело) Я даже пробовать боюсь... Спасибо вам за терпение! Добавлено через 1 минуту и 46 секунд
Конечно не легче.. Просто интерфейсы DLL функций и бинарный формат были обговорены. Не хотел менять. Сейчас пойду убеждать в необходимости параметра size) |
| Автор: azesmcar 18.6.2010, 12:56 | ||
Так формат не меняется, просто работать с данными надо начинать со смещения +2 и все, формат тот же, там одна арифметическая операция с указателем добавляется, думаю это просто. В любом случае, архитектура должна подстраиваться под нужды задачи а не наоборот. |
| Автор: bsa 18.6.2010, 15:11 |
| azesmcar, думаю, будет логичней в функции передавать не void*, а const Buffer *. где Buffer это структура типа { size_t size; void *data; }. По сути, это твой же вариант, только более красивый. |
| Автор: azesmcar 18.6.2010, 15:15 | ||
ну автор не хотел менять интерфейс DLL, а вообще да, согласен |
| Автор: Earnest 18.6.2010, 15:47 |
Только не 2, а как минимум 4. Икнуть не успеешь, как 64 К перестанет хватать... Насчет структуры... не знаю... плотный поток данных иногда бывает более предпочтительным. Тем более, что никто не мешает написать: struct CBufffer { size_t m_Size; BYTE mBuf[1]; }; если уж с указателями возиться влом. |
| Автор: azesmcar 18.6.2010, 18:24 | ||
Ну да, я писал об этом в самом начале, это уже в зависимости от задачи |
| Автор: Superklug 22.6.2010, 13:49 |
| В итоге написал функции для сериализации/десериализации непосредственно для void*. В случае ошибки всплывает исключение memory access. Вроде все нормально работает... |