1

我正在尝试将对象(包括对象向量)保存在二进制文件中。

这是文件代码的一些负载:

template <class T> void read(T* obj,std::ifstream * file) {
    file->read((char*)(obj),sizeof(*obj));
    file->seekg(int(file->tellg())+sizeof(*obj));
}

void read_db(DB* obj,std::ifstream * file) {
    read<DB>(obj,file);
    for(int index = 0;index < obj->Arrays.size();index++) {
        std::cin.get(); //debugging
        obj->Arrays[0].Name = "hi"; //debugging
        std::cin.get(); //debugging
        std::cout << obj->Arrays[0].Name;
        read<DB_ARRAY>(&obj->Arrays[index],file);
        for(int row_index = 0;row_index < obj->Arrays[index].Rows.size();row_index++) {
            read<DB_ROW>(&obj->Arrays[index].Rows[row_index],file);
            for(int int_index = 0;int_index < obj->Arrays[index].Rows[row_index].i_Values.size();int_index++) {
                read<DB_VALUE<int>>(&obj->Arrays[index].Rows[row_index].i_Values[int_index],file);
            }
        }
    }
}

这是 DB/DB_ARRAY 类

class DB {
public:
    std::string Name;
    std::vector<DB_ARRAY> Arrays;
    DB_ARRAY * operator[](std::string);
    DB_ARRAY * Create(std::string);
};
class DB_ARRAY {
public:
    DB* Parent;
    std::string Name;
    std::vector<DB_ROW> Rows;
    DB_ROW * operator[](int);
    DB_ROW * Create();
    DB_ARRAY(DB*,std::string);
    DB_ARRAY();
};

所以现在 read_db 函数的第一个参数将具有正确的值,并且对象上的向量数组具有正确的大小,但是如果我从 obj->Arrays 索引任何对象的任何值,它将引发访问冲突异常。

std::cout << obj->Arrays[0].Name; // error
std::cout << &obj->Arrays[0]; // no error

后者总是打印相同的地址,所以当我保存一个转换为 char* 的对象时,它是否也保存了它的地址?

4

2 回答 2

0

文件中二进制数据的格式是什么?在您指定之前,我们无法告诉您如何编写它。基本上,您必须为所有数据类型指定格式(除了char),然后编写代码以逐字节写出该格式(或将其生成到缓冲区中);另一方面,逐字节读取它,并重建它。C++ 标准没有(或很少)说明数据类型的大小和表示,除了必须sizeof(char)为 1,并且unsigned char必须是所有位的纯二进制表示。在我今天可以访问的机器上(Sun Sparc 和 PC),只有字符类型有一个共同的表示。至于更复杂的类型,值表示中使用的内存甚至可能不是连续的: std::vector例如 an 的按位表示通常是三个指针,向量中的实际值完全在其他地方找到。

这些函数istream::readostream::write旨在将数据读入缓冲区以进行手动解析,并写入预先格式化的缓冲区。您需要使用 a reinterpret_cast来使用它们的事实应该很好地表明它不起作用。

于 2012-10-11T16:16:07.653 回答
0

正如各种评论者指出的那样,您不能简单地通过保存/恢复它的内存来序列化(非 POD)对象。

实现序列化的常用方法是在类上实现序列化接口。像这样的东西:

struct ISerializable {
   virtual std::ostream& save(std::ostream& os) const = 0;
   virtual std::istream& load(std::istream& is) = 0;
};

然后你在你的可序列化类中实现这个接口,递归调用saveload引用其他可序列化类的任何成员,并写出任何 POD 成员。例如:

class DB_ARRAY : public ISerializable {
public:
    DB* Parent;
    std::string Name;
    std::vector<DB_ROW> Rows;
    DB_ROW * operator[](int);
    DB_ROW * Create();
    DB_ARRAY(DB*,std::string);
    DB_ARRAY();

   virtual std::ostream& save(std::ostream& os) const
   {
       // serialize out members
       return os;
   }

   virtual std::istream& load(std::istream& is)
   {
       // unserialize members
       return os;
   }
};

正如count0所指出的,boost::serialization也是一个很好的起点。

于 2012-10-11T15:16:47.577 回答