2010-06-22 2 views
3

В прекрасном мире C# я могу создать поток памяти без указания его размера, записать в него, а затем просто взять базовый буфер.ищет MemoryStream в C++

Как я могу сделать то же самое в C++? в основном мне нужно:

memory_stream ms(GROW_AS_MUCH_AS_YOU_LIKE); 

ms << someLargeObjects << someSmallObjects << someObjectsWhosSizeIDontKnow; 

unsigned char* buffer = ms.GetBuffer(); 
int bufferSize = ms.GetBufferSize(); 

rawNetworkSocket.Send(buffer, bufferSize); 

Кстати, у меня есть стимул в моем проекте, хотя я не так уж хорошо знаком с ним.

спасибо.

+0

@Martin: Я не хочу, я хочу создать поток, заполнить его, взять базовый буфер и отправить его. также я не могу использовать boost :: socket, я использую протокол костюма по API WINSOCK, поэтому все, что я могу отправить, это весь буфер. –

ответ

5
#include <sstream> 

std::ostringstream buffer; // no growth specification necessary 
buffer << "a char buffer" << customObject << someOtherObject; 

std::string contents = buffer.str(); 
size_t bufferSize = contents.size(); 

rawNetworkSocket.Send(contents); // you can take the size in Send 

Используя этот подход, вы должны разобрать результат, где вы получите его (как код выше только преобразует ваши данные в неструктурированных строку.

Еще одна проблема в том, что, поскольку C++ не . поддержка отражение, вы должны определить оператор < < для ваших объектов Это код для Custom класса:

template<typename C, typename T> 
std::basic_ostream<C,T>& operator << (
    std::basic_ostream<C,T>& out, const Custom& object) 
{ 
    out << object.member1 << "," << object.member2 /* ... */ << object.memberN; 
    return out; 
} 

Если вы хотите структурированные сериализации, взглянуть на boost::serialization.

2

Для этой цели вы можете посмотреть std::stringstream. Поток будет расти по мере необходимости. Если вы не хотите оставить объекты в двоичном формате вместо ASCII, в этом случае вы можете взглянуть на объекты и реализации streambuf.

Обратите внимание, что C++ не имеет отражения или двойную/множественную диспетчеризацию, так что вы должны будете предоставить поддержку неизвестного размера объекта самостоятельно:

class unknown_base { 
    virtual void dump(std::ostream &) const; 
}; 
std::ostream& operator<<(std::ostream& o, unknown_base const & obj) { 
    obj.dump(o); 
    return o; 
} 
std::string serialize(std::vector<unknown_base*> const & data) { 
    std::ostringstream st; 
    for (std::vector<unknown_base*>::const_iterator it = data.begin(), end = data.end(); 
     it != end; ++it) { 
     st << **it; // double dereference: iterator, pointer 
    } 
    return st.str(); 
} 
+0

Почему 'std :: stringstream' не работает для двоичных объектов? Он может работать над чем угодно. Просто напишите или << любую вещь, которую вы хотите, и получите результирующий объект 'std :: string', который может содержать что угодно, включая' 0' (символ окончания строки символов C), который не имеет такого же значения в середине строка 'std :: string', –

+0

@Didier - соглашение о том, что оператор << в ostream записывает что-то читаемое человеком. –

+0

@Pete: Вы также можете использовать функцию write() для элемента 'std :: stringstream'. –

0

Поскольку вы говорите о сети, это кажется ужасно, как вы хотите создать какое-то сообщение и отправить его по кабелю.

Существуют библиотеки для создания сообщений и создания API для этих сообщений, наиболее известными из которых являются протоколы Google Protocol (protobuf). Это позволяет описать синтаксис вашего сообщения в коротком файл (пользовательский формат), а затем автоматически генерировать API для декодирования этого сообщения в C++/Python/Java

Преимущества:

  • взаимодействия, которые также означает возможность проверки сообщения с помощью языка сценариев здесь, при необходимости отладки.
  • обработка версии (совместимость в обратном направлении и вперед), потому что мы знаем, что вы скоро измените сообщение, но, возможно, не обновите все сразу
  • text/binary output. Текст удобен для отладки, Binary требуется, когда каждый бит рассчитывать

Кроме того, можно использовать вывод текста и сжать его с LZO или такой, чтобы получить некоторое пространство :)

+0

это было бы здорово, но у меня уже есть собственный протокол и API для передачи сообщений, а мои сообщения будут в xml, а моя клиентская сторона - C# ... Что я думал сделать, это использовать boost: : сериализация для передачи моих сообщений в xml, взять сгенерированный поток, взять буфер и отправить как есть на стороне C# –

+0

Не используйте для этого сериализацию. Он связывает две отдельные сущности вместе. Вы могли бы отлично написать генератор C# API для Google (учитывая, что они воюют с Microsoft, они вряд ли сделают это сами). Или используйте другую схему обмена. Но сериализация предназначена для того же двоичного файла для декодирования объекта, если у вас есть одно поле для одного объекта, тогда вы должны немедленно обновить C# или просто перестать работать ... и вы должны иметь ту же модель на стороне C# тоже: это адский уход. Вам необходимо определить формальный интерфейс (xml, если вам нужно:/или json и т. Д.). –

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