繁体   English   中英

序列化包含 std::string 的 class

[英]Serializing a class which contains a std::string

我不是 c++ 专家,但我过去曾多次对事物进行序列化。 不幸的是,这一次我试图序列化一个包含std::string的 class ,我理解这很像序列化指针。

我可以将 class 写出到文件中,然后再次读回。 所有int字段都很好,但std::string字段给出了“地址越界”错误,大概是因为它指向不再存在的数据。

有没有标准的解决方法? 我不想 go 回到char arrays,但至少我知道他们在这种情况下工作。 如有必要,我可以提供代码,但我希望我已经很好地解释了我的问题。

我通过将 class 转换为char*并将其写入带有std::fstream的文件来进行序列化。 阅读当然正好相反。

我通过将 class 转换为 char* 并使用 fstream 将其写入文件来进行序列化。 阅读当然正好相反。

不幸的是,这仅在不涉及指针的情况下才有效。 你可能想给你的类void MyClass::serialize(std::ostream)void MyClass::deserialize(std::ifstream) ,然后调用它们。 对于这种情况,您需要

std::ostream& MyClass::serialize(std::ostream &out) const {
    out << height;
    out << ',' //number seperator
    out << width;
    out << ',' //number seperator
    out << name.size(); //serialize size of string
    out << ',' //number seperator
    out << name; //serialize characters of string
    return out;
}
std::istream& MyClass::deserialize(std::istream &in) {
    if (in) {
        int len=0;
        char comma;
        in >> height;
        in >> comma; //read in the seperator
        in >> width;
        in >> comma; //read in the seperator
        in >> len;  //deserialize size of string
        in >> comma; //read in the seperator
        if (in && len) {
            std::vector<char> tmp(len);
            in.read(tmp.data() , len); //deserialize characters of string
            name.assign(tmp.data(), len);
        }
    }
    return in;
}

您可能还希望重载 stream 运算符以便于使用。

std::ostream &operator<<(std::ostream& out, const MyClass &obj)
{obj.serialize(out); return out;}
std::istream &operator>>(std::istream& in, MyClass &obj)
{obj.deserialize(in); return in;}

简单地将 object 的二进制内容写入文件不仅不可移植,而且正如您所认识到的,它不适用于指针数据。 您基本上有两个选择:或者您编写一个真正的序列化库,通过例如使用c_str()到 output 文件的实际字符串来正确处理 std::strings,或者您使用出色的boost 序列化库。 如果可能的话,我会推荐后者,然后您可以使用这样的简单代码进行序列化:

#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/serialization/string.hpp>

class A {
    private:
        std::string s;
    public:
        template<class Archive>
        void serialize(Archive& ar, const unsigned int version)
        {
            ar & s;
        }
};

在这里,function serialize用于序列化和反序列化数据,具体取决于您如何调用它。 有关更多信息,请参阅文档。

对于具有可变大小的字符串或其他 blob,最简单的序列化方法是在序列化整数时首先序列化大小,然后将内容复制到 output stream。

读取时首先读取大小,然后分配字符串,然后通过从 stream 读取正确的字节数来填充它。

另一种方法是使用定界符和 escaping,但需要更多代码并且在序列化和反序列化时速度较慢(但结果可以保持人类可读)。

如果您的 class 包含任何外源数据( string ),则您必须使用比将 class 转换为char*并将其写入文件更复杂的序列化方法。 你是正确的,为什么你会遇到分段错误。

我会创建一个成员 function ,它将获取一个fstream并从中读取数据,以及一个反向 function ,它将获取一个fstream并将其内容写入它以便稍后恢复,如下所示:

class MyClass {
pubic:
    MyClass() : str() { }

    void serialize(ostream& out) {
        out << str;
    }

    void restore(istream& in) {
        in >> str;
    }

    string& data() const { return str; }

private:
    string str;
};

MyClass c;
c.serialize(output);

// later
c.restore(input);

您还可以定义operator<<operator>>以使用istreamostream来序列化和恢复您的 class 以及如果您想要该语法糖。

为什么不只是类似的东西:

std::ofstream ofs;
...

ofs << my_str;

接着:

std::ifstream ifs;
...

ifs >> my_str; 
/*!
 * reads binary data into the string.
 * @status : OK.
*/

class UReadBinaryString
{
    static std::string read(std::istream &is, uint32_t size)
    {
        std::string returnStr;
        if(size > 0)
        {
            CWrapPtr<char> buff(new char[size]);       // custom smart pointer
            is.read(reinterpret_cast<char*>(buff.m_obj), size);
            returnStr.assign(buff.m_obj, size);
        }

        return returnStr;
    }
};

class objHeader
{
public:
    std::string m_ID;

    // serialize
    std::ostream &operator << (std::ostream &os)
    {
        uint32_t size = (m_ID.length());
        os.write(reinterpret_cast<char*>(&size), sizeof(uint32_t));
        os.write(m_ID.c_str(), size);

        return os;
    }
    // de-serialize
    std::istream &operator >> (std::istream &is)
    {
        uint32_t size;
        is.read(reinterpret_cast<char*>(&size), sizeof(uint32_t));
        m_ID = UReadBinaryString::read(is, size);

        return is;
     }
};

我很久没有编码 C++ 了,但也许你可以序列化一个char数组。

然后,当您打开文件时,您的string将只指向数组。

只是一个想法。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM