2012-07-05 114 views
5

我想要二進制序列化向量的數據。在下面的示例中,我將序列化爲一個字符串,然後反序列化爲一個向量,但不會獲得我開始使用的相同數據。爲什麼會這樣?向量序列化

vector<size_t> v; 
v.push_back(1); 
v.push_back(2); 
v.push_back(3); 

string s((char*)(&v[0]), 3 * sizeof(size_t)); 

vector<size_t> w(3); 
strncpy((char*)(&w[0]), s.c_str(), 3 * sizeof(size_t)); 

for (size_t i = 0; i < w.size(); ++i) { 
    cout << w[i] << endl; 
} 

我希望得到的輸出

1 
2 
3 

而是得到輸出

1 
0 
0 

(上gcc-4.5.1

+0

@Mark:我不認爲是這樣。 – 2012-07-05 23:28:24

回答

4

的錯誤是在調用strncpy。從鏈接的頁面:

如果SRC的長度小於Ñ,函數strncpy()焊盤dest的與空字節的餘數。

所以,在串行化數據中的第一字節0發現後w的數據陣列的剩餘部分被填充有0秒。

爲了解決這個問題,使用一個for環,或std::copy

std::copy(&s[0], 
      &s[0] + v.size() * sizeof(size_t), 
      reinterpret_cast<char *>(w.data())); 

IMO,而是採用std::string作爲緩衝劑,只要使用一個char數組來保存序列化的數據。

Example上ideone

+0

'strncpy'上的好消息,我從來不知道那個「特性」,並且對他的代碼爲什麼不起作用感到困惑。 – 2012-07-05 23:48:34

+0

謝謝你的解釋。爲什麼std :: copy比memcpy好? – typedef 2012-07-06 00:06:33

+0

由於您正在複製一個整數數組,兩者的工作原理都是一樣的。但讓我們說,矢量包含一個管理一些資源的對象。 memcpy會執行該對象的按位副本,這很可能不是您希望它複製的方式。另一方面,std :: copy會調用賦值操作符,確保對象被正確複製。 – Praetorian 2012-07-06 00:15:30

2

strncpy是失敗的一個巨大的一堆。它會在你的輸入提前終止,因爲size_t有一些零字節,它解釋爲NULL終止符,將它們保留爲缺省構造0.如果你在BE計算機上運行此測試,則全部爲0.使用std::copy

-1

要將此矢量序列化爲一個字符串,首先要將此矢量的每個元素從一個int轉換爲一個包含相同數字的ascii表示的字符串,此操作可以稱爲int的序列化串起來。

因此,例如,假設一個整數爲10位,我們可以

// create temporary string to hold each element 
char intAsString[10 + 1]; 

然後整數轉換爲字符串

sprintf(intAsString, "%d", v[0]); 

itoa(v[0], intAsString, 10 /*decimal number*/); 

您還可以使用的ostringstream和< <運營商

如果您查看intAsString和v [0]的內存內容,它們非常不同,第一個包含表示十進制數系統中v [0]的值的ascii字母(基數爲10),而v [0]包含數字的二進制表示(因爲這是計算機如何存儲數字)。

+1

在我看來很清楚他想要二進制序列化,而不是文本序列化。另外,C++代碼中的'sprintf'和'itoa'? – 2012-07-05 23:26:02

+0

好吧,他做了一個字符串來保存輸出,這就是爲什麼我認爲他想要文本序列化。 感謝您的評論:) – 2012-07-05 23:32:04

+0

不,該字符串被複制到一個向量,並且向量保存輸出。該字符串僅僅是一個二進制緩衝區。 – 2012-07-05 23:33:31

-1

最安全的方法是循環遍歷向量並將值分別存儲到大小爲3 * sizeof(size_t)的char數組中。這樣你就不需要依賴矢量類實現的內部結構。

+0

矢量和字符串都保證是連續的,並且在C++ 11中沒有填充,所以這不是問題。 – 2012-07-05 23:35:03