【发布时间】:2020-09-12 12:29:21
【问题描述】:
我正在尝试关注https://accu.org/index.php/journals/2317 上写的一篇文章 现在我发现这很有趣,因为我正在尝试深入研究我正在开发的一些管理工具的序列化/文件保存/加载。我将它标记为 c++,因为在我让它工作后我会将它包装在一个类中(希望在你的帮助下)。
现在,这是出于学习目的,因为我目前不打算使用 boost 或任何其他序列化库。我想知道或尝试找出这些方法是否有效。
目前,为了工作,我不得不做一些细微的修改,因为断言总是错误的,并且在尝试使用 memcpy 写入外部分配的内存时遇到问题。
现在,它可以编译,但是当我对结构进行序列化和反序列化时,数据不一样。
请查看并帮助我,或指出正确的方向。在代码之后,我将尝试解释我是如何理解它的。
#include <iostream>
#include <cassert>
struct Y
{
int yy;
};
struct X
{
int xx;
struct Y* y = nullptr;
int z;
};
// Changed OutMemStram and InMemStream for IOMemStream, same data
struct IOMemStream
{
// changed from uint8_t* to char*
char* pp;
char* ppEnd;
};
// Output
inline void WriteToStream( IOMemStream* dst, void* p, size_t sz )
{
dst->pp = (char*)p; // original code doesn't contain this line
dst->ppEnd = (char*)p + sz; // original code doesn't contain this line
assert( (dst->pp + sz) <= dst->ppEnd );
memcpy( dst->pp, p, sz );
dst->pp += sz;
}
void SerializeX( IOMemStream* dst, X* x )
{
WriteToStream( dst, x, sizeof( X ) );
WriteToStream( dst, x->y, sizeof( Y ) );
}
// Input
inline void ReadFromStream( IOMemStream* src, void* p, size_t sz )
{
//assert( (src->pp + sz) <= src->ppEnd );
memcpy( p, src->pp, sz );
src->pp += sz;
}
void DeserializeX( IOMemStream* src, X* x )
{
ReadFromStream( src, x, sizeof( X ) );
// x->y contains garbage at this point(!)
// ok, not exactly garbage - but a pointer
// which is utterly invalid in our current space
x->y = new Y;
assert( x->y );
ReadFromStream( src, x->y, sizeof( Y ) );
}
// Usage sample
int main()
{
// Assume struct x was previously filled by other function
X x;
x.xx = 1000;
x.z = 2000;
x.y = new Y;
x.y->yy = 3000;
// IO buffer
IOMemStream ioms;
// Test for output
SerializeX( &ioms, &x );
// Test for input
X x1;
DeserializeX( &ioms, &x1 );
// x1.xx should be 1000 and x1.< should be 2000
std::cout << x1.xx << ", " << x1.z << std::endl;
delete x.y;
delete x1.y;
//delete ioms.pp; // gets exception
std::cin.get();
return 0;
}
这是我理解(或不理解)的方式。
- 结构 X,包含 2 个整数和 1 个指向 Y 结构的结构指针,假设整数大小 = 4,则 X 的 大小将为 12 个字节。是的,它是 4 个字节。
- IOMemStream 包含结构 X 和结构 Y 的指针。
- IOMemStream->pp 和 IOMemStream->ppEnd 应该有 12 个字节和 4 个字节来自 struct X 和 X->Y。
- 函数 WriteToStream 将结构中的字节打包到 pp 和ppEnd指针,X赋值后,指针递增 按大小为 Y 结构做好准备。 (在原始文章中, 断言是在没有分配变量 pp 和 ppEnd 的情况下进行的
- IOMemStream) 函数 SerializeX 对 X 和 Y 使用 WriteToStrea 结构。
反序列化几乎相同,但顺序相反,ReadFromStream 将为结构 Y 分配内存。
我从这里迷路了,因为序列化和反序列化的值不一样。另外,我希望我能正确理解:D
提前谢谢你!
【问题讨论】:
-
你是在 valgrind 下运行这段代码,还是用地址清理器编译?
-
嗨!不,抱歉。需要调查 valgrind 或地址消毒剂是什么。我真的是一个新手,我在网上完成了一些 tuts,我正在尝试编写自己的工具并尝试将其他 ppl 的代码理解为 excercese。
-
//assert( (src->pp + sz) <= src->ppEnd );行被注释掉是否有特殊原因?这行代码在运行时可能会导致某种问题吗? -
是的,我评论它是因为断言总是错误的,即使它使用在 WriteToStream 上传递的同一个变量 (IOMemStream),其中断言是正确的。 (ioms.pp
-
也许你应该考虑一下为什么断言是错误的?也许,而且我知道这有很多问题要问,您应该问问自己,该断言是否可能可能出于某种原因?也许,不要误会,您可能忽略了与该断言相关的某些内容?
标签: c++ c serialization