2012-07-05 111 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