2010-06-22 106 views
3

在奇妙的C#世界中,我可以創建一個沒有指定其大小的內存流, 寫入它,然後只需要底層緩衝區。在C++中尋找一個MemoryStream

我該如何在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,我在WINSOCK API上使用了一個服裝協議,所以我可以發送的是一個完整的緩衝區。 – 2010-06-22 07:56:20

回答

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', – 2010-06-22 07:55:36

+0

@Didier約定是運算符<<給一個ostream寫入一些人類可讀的東西。 – 2010-06-22 08:05:43

+0

@Pete:你也可以使用'std :: stringstream'的write()成員函數。 – 2010-06-22 08:29:51

0

既然你是在談論網絡時,它似乎非常喜歡你想要創建某種消息並通過網絡發送。

有些庫可以爲這些消息創建消息並生成API,其中最着名的是Google協議緩衝區(簡稱protobuf)。它可以讓你描述你的消息的語法在很短的文件(自定義格式),然後自動生成API此消息在C++/Python的/ Java的解碼

優點包括:

  • 互操作性,這也意味着在這裏用腳本語言檢查消息的可能性,在調試時很方便。
  • 版本處理(向後和向前兼容性),因爲我們知道您將盡快修改消息,但可能不會立即升級所有內容
  • text/binary output。文本是非常方便的調試,二進制當每個位計數

而且是必需的,它可以使用文本輸出,並與LZO壓縮,或如獲得一些空間:)

+0

這將是偉大的,但我已經有一個自定義協議和API傳遞消息,我的消息將在xml中,我的客戶端是C#... 我想要做的是使用boost: :序列化將我的消息傳輸到xml,將生成的流作爲緩衝區併發送到C#端 – 2010-06-22 08:02:30

+0

不要使用序列化。它將兩個獨立的實體聯繫在一起。你可以爲Google編寫一個C#API生成器(鑑於他們與微軟的戰爭,他們不太可能自己做)。或者使用另一種通訊方案。但是,序列化是爲了解碼對象的同一個二進制文件,如果你只有一個對象到一個對象,那麼你必須立即更新C#端或者它只是停止工作......並且你必須在C#端有相同的模型太:它是一個維護地獄。你需要定義一個正式的接口(如果你必須:/或JSON等...)。 – 2010-06-22 17:06:18