首先:在你的课堂上使用 std::string 从长远来看,它会让你的生活变得更轻松。
但这个建议对 std::string 和 char* 都有效(稍作调整应该很明显)。
基本上你想序列化未知大小的数据(在编译时)。这意味着当您对数据进行反序列化时,您必须拥有一种技术来告诉您数据有多长(以大小为对象添加前缀)或找到数据结尾的方法(终止标记)。
终止标记更容易进行序列化。但反序列化更难(因为您必须向前寻找结尾)。此外,您必须转义对象中出现的任何终止标记,并且反序列化必须知道转义并将其删除。
因此,由于这种复杂性,我不想使用终止标记。结果,我在对象前面加上了一个大小。这样做的代价是我必须以不会破坏的方式对对象的大小进行编码。
所以如果我们在一个对象前面加上它的大小,你可以这样做:
// Place a ':' between the string and the size.
// There must be a marker as >> will continue reading if
// fname contains a digit as its first character.
// I don;t like using a space as >> skips spaces if you are not carefull
// and it is hard to tell the start of the string if the first characters in fname
// are the space character.
std::cout << strlen(fname) << ":" << fname;
然后你可以像这样反序列化:
size_t size;
char mark;
std::cint >> size >> mark;
if (!std::cin || mark != ':')
{ throw BadDataException;
}
result = new char[size+1](); // Note the () to zero fill the array.
std::cin.read(result, size)
编辑 1(基于 cmets)更新:与字符串一起使用:
size_t size;
char mark;
std::cint >> size >> mark;
if (!std::cin || mark != ':')
{ throw BadDataException;
}
std::string result(' ', size); // Initialize string with enough space.
std::cin.read(&result[0], size) // Just read directly into the string
编辑 2(基于评论)
序列化字符串的辅助函数
struct StringSerializer
{
std::string& value;
StringSerializer(std::string const& v):value(const_cast<std::string&>(v)){}
friend std::ostream& operator<<(std::ostream& stream, StringSerializer const& data)
{
stream << data.value.size() << ':' << data.value;
}
friend std::istream& operator>>(std::istream& stream, StringSerializer const& data)
{
std::size_t size;
char mark(' ');
stream >> size >> mark;
if (!stream || mark != ':')
{ stream.setstate(std::ios::badbit);
return stream;
}
data.value.resize(size);
stream.read(&data.value[0], size);
}
};
序列化一个人
std::ostream& operator<<(std::ostream& stream, Person const& data)
{
return stream << StringSerializer(data.fname) << " "
<< StringSerializer(data.lname) << " "
<< data.age << "\n";
}
std::istream& operator>>(std::istream& stream, Person& data)
{
stream >> StringSerializer(data.fname)
>> StringSerializer(data.lname)
>> data.age;
std::string line;
std::getline(stream, line);
if (!line.empty())
{ stream.setstate(std::ios::badbit);
}
return stream;
}
用法:
int main()
{
Person p;
std::cin >> p;
std::cout << p;
std::ofstream f("data");
f << p;
}