C++ 用C+;中的指针序列化类+;

C++ 用C+;中的指针序列化类+;,c++,serialization,pointers,C++,Serialization,Pointers,我想序列化类型为Person的对象。我想稍后使用它来保存数据,甚至保存游戏。我知道如何处理诸如int、char、bool,甚至像char[]这样的c字符串之类的原语 问题是,我希望字符串尽可能大,而不是声明一个大小为256的char数组,希望没有人输入太大的内容。我读到用std::string作为成员序列化一个类是行不通的,因为它有一个内部指针,但是有没有办法序列化我的类,它有一个char*作为成员 我意识到Boost有一个序列化库,但我想在不需要外部库的情况下实现这一点,这似乎是一个值得尝试的

我想序列化类型为
Person
的对象。我想稍后使用它来保存数据,甚至保存游戏。我知道如何处理诸如
int
char
bool
,甚至像
char[]
这样的c字符串之类的原语

问题是,我希望字符串尽可能大,而不是声明一个大小为256的
char
数组,希望没有人输入太大的内容。我读到用
std::string
作为成员序列化一个类是行不通的,因为它有一个内部指针,但是有没有办法序列化我的类,它有一个
char*
作为成员

我意识到Boost有一个序列化库,但我想在不需要外部库的情况下实现这一点,这似乎是一个值得尝试的好活动

这是我的
个人
课程:

class Person
{
private:
   char* _fname; 
   char* _lname;

public:
   Person();
   Person(const char* fname, const char* lname);
   Person(const string& fname, const string& lname);

   string fname() const;
   void fname(const char* fname);
   void fname(const string& fname);

   string lname() const;
   void lname(const char* lname);
   void lname(const string& lname);
};

您不能序列化指针,您需要序列化指向的数据指针

您将需要序列化整个对象网络,从
个人
(或
游戏
)开始,查看每个对象,这些对象可以从您的开始对象访问


反序列化时,您从存储器中读取数据,为该数据分配内存,并将此新分配内存的地址用作
Person
/
Game
object

指针字段的成员,这会使序列化更困难,但并非不可能。如果您不想使用任何序列化库,以下是您可以使用的方法

您应该确定序列化时指向的对象的大小(例如,它可能是固定大小的,也可能是结尾带有空字符的C字符串),然后可以保存一个标记,指示您正在序列化一个间接对象以及指向的区域的大小和实际内容


当您在反序列化过程中偶然发现该标记时,您可以分配适当的内存量,将对象复制到其中,并将指向反序列化对象中区域的指针存储起来。

首先:在类中使用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;
编辑1(基于注释)更新:与字符串一起使用: 编辑2(基于评论) 用于序列化字符串的Helper函数

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);
    }
};
struct-StringSerializer
{
std::字符串和值;
StringSerializer(std::stringconst&v):值(const_cast(v)){}
friend std::ostream&operator>mark;
如果(!stream | | mark!=':')
{stream.setstate(std::ios::badbit);
回流;
}
数据。值。调整大小(大小);
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;
}
std::ostream&operator data.age;
std::字符串行;
std::getline(流,行);
如果(!line.empty())
{stream.setstate(std::ios::badbit);
}
回流;
}
用法:

int main()
{
    Person p;
    std::cin  >> p;
    std::cout << p;

    std::ofstream  f("data");
    f << p;
}
intmain()
{
人p;
标准:cin>>p;

std::cout我建议使用向量来封装 序列化

#include <vector>
using namespace std;
map vector<unsigned char> cbuff;
inline cbuff vchFromString(const std::string &str) {
unsigned char *strbeg = (unsigned char*) str.c_str();
  return cbuff(strbeg, strbeg + str.size());
}
inline std::string stringFromVch(const cbuff &vch) {
 std::string res;
 std::vector<unsigned char>::const_iterator vi = vch.begin();
 while (vi != vch.end()) {
  res += (char) (*vi);
  vi++;
 }
 return res;
}

class Example
{
  cbuff label;
  Example(string labelIn)
  {
    SetLabel(labelIn);
  }
  IMPLEMENT_SERIALIZE
  (
    READWRITE(label);
  )
  void SetLabel(string labelIn)
  {
    label = vchFromString(labelIn);
  }
  string GetLabel()
  {
    return (stringFromVch(label));
  }
};
#包括
使用名称空间std;
映射向量cbuff;
内联cbuff vchFromString(const std::string&str){
无符号字符*strbeg=(无符号字符*)str.c_str();
返回cbuff(strbeg,strbeg+str.size());
}
内联标准::字符串stringFromVch(常量cbuff&vch){
std::string res;
std::vector::const_迭代器vi=vch.begin();
while(vi!=vch.end()){
res+=(char)(*vi);
vi++;
}
返回res;
}
课例
{
cbuff标签;
示例(字符串标签)
{
SetLabel(labelIn);
}
实现_序列化
(
读写(标签);
)
无效设置标签(字符串标签)
{
标签=vchFromString(labelIn);
}
字符串GetLabel()
{
返回(stringFromVch(标签));
}
};

如何序列化a
char*
指向的数据?请原谅,我对指针不太在行,但解引用指针(如
*\u lname
)不只是返回第一个字符吗?在C
中,char*
是表示“字符串”的标准方式“代码”>“LoNo.<代码”指向第一个字符,字符串一直持续到第一个零字节。在C++中,最好使用<代码> STD::String < /Cord>表示“string”,但仍然需要通过<代码> STD::Str::CyString()来获得第一个字符的指针。
序列化时。为什么一开始就有裸指针?你喜欢痛苦吗?我很想使用
std::string
,但有人告诉我,用它作为成员序列化一个类可能非常棘手。
char
数组我想也可以,但你必须知道编译时的长度。不幸的是,我不能Lp有信念和信念的东西,但是如果我和某人谈论关于我喜欢的C++,我会尽力让他们使用<代码> STD::String 。有可能用<代码> STD::String < /Cord>完成序列化,不过,别误会,我真的想用它,我喜欢<代码> STD::String ,但是它似乎不起作用。uld将其作为一个问题发布!(现在我们这里有一个真实的XZ情况:-)寿
int main()
{
    Person p;
    std::cin  >> p;
    std::cout << p;

    std::ofstream  f("data");
    f << p;
}
#include <vector>
using namespace std;
map vector<unsigned char> cbuff;
inline cbuff vchFromString(const std::string &str) {
unsigned char *strbeg = (unsigned char*) str.c_str();
  return cbuff(strbeg, strbeg + str.size());
}
inline std::string stringFromVch(const cbuff &vch) {
 std::string res;
 std::vector<unsigned char>::const_iterator vi = vch.begin();
 while (vi != vch.end()) {
  res += (char) (*vi);
  vi++;
 }
 return res;
}

class Example
{
  cbuff label;
  Example(string labelIn)
  {
    SetLabel(labelIn);
  }
  IMPLEMENT_SERIALIZE
  (
    READWRITE(label);
  )
  void SetLabel(string labelIn)
  {
    label = vchFromString(labelIn);
  }
  string GetLabel()
  {
    return (stringFromVch(label));
  }
};