这是您的内容应如何阅读:
#include
#include
#include
struct SerializeTestStruct
{
char mCharVal;
unsigned int mIntVal;
void Serialize(::std::ostream &os);
static SerializeTestStruct Deserialize(::std::istream &is);
};
void SerializeTestStruct::Serialize(std::ostream &os)
{
if (os.good())
{
os.write((char*)&mCharVal, sizeof(mCharVal));
os.write((char*)&mIntVal, sizeof(mIntVal));
}
}
SerializeTestStruct SerializeTestStruct::Deserialize(std::istream &is)
{
SerializeTestStruct retval;
if (is.good())
{
is.read((char*)&retval.mCharVal, sizeof(retval.mCharVal));
is.read((char*)&retval.mIntVal, sizeof(retval.mIntVal));
}
if (is.fail()) {
throw ::std::runtime_error(\"failed to read full struct\");
}
return retval;
}
int main(int argc, const char *argv[])
{
//ultra basic serialization test.
// setup
const ::std::string testFileName = \"test.bin\";
// write
{
SerializeTestStruct testStruct;
testStruct.mCharVal = \'y\';
testStruct.mIntVal = 9;
::std::ofstream fileOut(testFileName.c_str());
fileOut.open(testFileName.c_str(),
std::ofstream::binary|std::ofstream::out);
fileOut.clear();
testStruct.Serialize(fileOut);
}
// read
{
::std::ifstream fileIn (testFileName.c_str(),
std::ifstream::in|std::ifstream::binary);
if (fileIn.is_open())
{
SerializeTestStruct testStruct = \\
SerializeTestStruct::Deserialize(fileIn);
::std::cout << \"testStruct.mCharVal == \'\" << testStruct.mCharVal
<< \"\' && testStruct.mIntVal == \" << testStruct.mIntVal
<< \'\\n\';
}
}
return 0;
}
样式问题:
如果可以帮助,请勿使用ѭ7进行创建。堆栈分配的对象通常是您想要的,并且比从堆分配的任意生存期对象要容易得多。如果您确实使用new,请考虑使用某种智能指针类型来帮助您管理生命周期。
序列化和反序列化代码应匹配,以便可以一起检查和更改它们。这使得此类代码的维护更加容易。
依靠C ++可以使用析构函数为您清理内容,这就是它们的用途。这意味着如果所用变量的范围相对有限,则使基本块包含代码的一部分。
不必使用标志。
错误...
不要使用::std::string的data成员函数。
使用位置ѭ7和那个内存块实在是一个坏主意,因为它非常复杂。而且,如果您确实使用过它,那么您将不会像以前那样使用数组删除。最后,由于稍后说明的原因,它仍然无法正常工作。
不要在Serialize函数采用的类型中使用ofstream,因为它是派生类,不需要您的功能。除非有非常特殊的理由,否则应始终在具有所需功能的层次结构中使用最基本的类。 Serialize与with15ѭ基类的功能配合良好,请改用该类型。
您的结构的磁盘上布局与内存中的布局不匹配,因此您的放置新技术注定会失败。通常,如果具有serialize函数,则需要匹配的deserialize函数。
这是您的内存布局问题的进一步说明。在基于x86_64的Linux机器上的内存中的结构如下所示:
+------------+-----------+
|Byte number | contents |
+============+===========+
| 0 | 0x79 |
| | (aka \'y\') |
+------------+-----------+
| 1 | padding |
+------------+-----------+
| 3 | padding |
+------------+-----------+
| 4 | padding |
+------------+-----------+
| 5 | 9 |
+------------+-----------+
| 6 | 0 |
+------------+-----------+
| 7 | 0 |
+------------+-----------+
| 8 | 0 |
+------------+-----------+
padding节的内容未定义,但通常为0。但这并不重要,因为该空间从未使用过,仅存在,因此对后面的ѭ21的访问位于有效的4字节边界上。
磁盘上结构的大小为5个字节,并且完全缺少填充部分。因此,这意味着当您将其读入内存时,它根本不会与内存结构完全对齐,并且访问它可能会导致某种可怕的问题。
第一条规则,如果需要serialize函数,则需要deserialize函数。第二条规则,除非您真的很清楚自己在做什么,否则不要将原始内存转储到文件中。在许多情况下,这都可以正常工作,但是在某些重要情况下,它将无法工作。并且,除非您知道什么有效,什么无效,什么时候该有效或不该有效,否则您最终将获得在某些测试情况下似乎可以正常工作的代码,但是当您尝试使用它时却惨败在真实的系统中。
我的代码仍然会将内存转储到文件中。只要您使用与编写时使用相同版本的编译器编译的代码在完全相同的体系结构和平台上重新读取结果,它就应该起作用。一旦这些变量之一改变,所有的赌注都将关闭。