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たとえば、 のビット単位の表現は通常 3 つのポインターであり、ベクトル内の実際の値は完全に別の場所にあります。

関数istream::readと関数ostream::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;
};

次に、このインターフェイスをシリアライズ可能なクラスに実装し、他のシリアライズ可能なクラスを参照するメンバーを再帰的に呼び出しsaveloadPOD メンバーを書き出します。例えば:

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 に答える