2017-02-15 7 views
0

シリアルライブラリを使用してstd :: length例外に直面して、自分のクラスの完全なstd :: vectorをデシリアライズします。私はいくつかのコードを与えるのが最も簡単だと思います。これは私のクラスです:シリアル変換のトラブルシューティングPortableBinaryArchive

#include "cereal/archives/portable_binary.hpp" 
#include "cereal/archives/json.hpp" 
#include "cereal/types/vector.hpp" 

enum class myType { 
    None, unset, Type1, Type2, Type3 
}; 

class myClass 
{ 
public: 
    myClass(); 
    myClass(size_t siz); 
    ~myClass(); 
    std::vector<size_t> idxs; 
    myType dtype; 
    bool isvalid; 

    // This method lets cereal know which data members to serialize 
    template<class Archive> 
    void serialize(Archive & archive) 
    { 
     archive(CEREAL_NVP(dtype), CEREAL_NVP(isvalid), CEREAL_NVP(idxs)); 
    } 
protected: 
private: 
}; 

idxsメンバーは必ずしも同じサイズである必要はありません。 いくつかの計算の後、私はその後、私はシリアライズし、後で別のアプリケーションで非直列化する

std::vector<myClass> allData; 

を得ます。これは、直列化のために私のコードです:

std::ofstream ofile(allDataFilename.c_str()); 
if (ofile.good()) 
{ 
    cereal::PortableBinaryOutputArchive theArchive(ofile); 
    theArchive(allData); 
    //ofilefp.close(); // Do not close because of RAII where dtor of cereal archive does some work on file! 
} 
else 
{ 
    std::cout << "Serialization to portable binary archive failed. File not good." << "\n"; 
} 

生成されたデータファイルがnullのサイズではなく、すべてがゼロなので、ちょうどそれは結構です外見からではありません。 これは私が他のアプリケーションにデシリアライズするために行うものです:私はこのデシリアライズコードを実行すると

std::string allDataFilename("C:\\path\\to\\file\\data.dat"); 
std::ifstream infile(allDataFilename.c_str()); 
std::vector<myClass> myDataFromDisk; 
if (infile.good()) 
{ 
    cereal::PortableBinaryInputArchive inArchive(infile); 
    inArchive >> myDataFromDisk; 
} 
else 
{ 
    std::cout << "Data file unavailable." << "\n"; 
} 

、私は例外「のstd :: length_error」を取得します。どういうわけか、このエラーの関連する議論はhereですが、私にとっては私の場合には関係がないようです。 (それともですか?)私は穀物のドキュメントのこの部分は、ここで適用されるかどうかわからなかったので、私は、機能を保存/ /デ別々の負荷と直列化しようとした

可能性は、それがあります単一の内部直列化 メソッドを使用することをお勧めしますが、必要なときに分割メソッドを使用できます(たとえば、クラスをロードするときに に動的にメモリを割り当てる)。

私も(それが内部的にとにかく穀物で行われているように)forループベースの範囲で個別にidxsメンバーの各ベクトル要素をアーカイブしようとしたが、両方の事は助けにはなりませんでした。

両方のアプリケーションはVisual Studio 2015 Update 3でコンパイルされています。私は現在のシリアルv1.2.2を使用していますが、ビットシリアル化の結果を与えるシリアルv1.1.2でも試しました。

脇に:シリアルJSONアーカイブで動作します。しかし、ベクタメンバーがシリアライズに最初に来たとき、それはJSONでは動作しなかった私は

archive(CEREAL_NVP(dtype), CEREAL_NVP(isvalid), CEREAL_NVP(idxs)); 

にシリアライズコールを変更した後にのみ。しかし、これは完全に無関係かもしれません。

archive(CEREAL_NVP(idxs), CEREAL_NVP(dtype), CEREAL_NVP(isvalid)); 

今私の質問:

1)これは直列化が穀物で動作するようになっている方法ですか?

2)シリアル化関数を追加する必要がありますか?例えば。 enumクラスに?

答えて

0

AverageCoder

敬具 あなたのクラスで何も間違っては自分のシリアル化コードに関してではありません。 enumのシリアライゼーションを行う必要はありません。それはcereal/types/common.hppによって自動的にインクルードされます。フィールドがシリアル化される順序は関係ありません。

あなたのエラーは、読み込みと保存を実行する際にアーカイブを適切に使用しないことになります。シリアルはストリームとのすべてのインターフェイスを処理するため、シリアルアーカイブに直接ストリーミング演算子(<<または>>)を使用しないでください。シリアルウェブサイト上の例をもう一度見てみると、シリアルアーカイブとのやりとりがあるときはいつでも、それは()オペレータによって行われます。

バイナリデータを処理するストリームで操作する場合は、適切なフラグ(std::ios::binary)を使用していることを確認する必要があります。これにより、デバッグが困難な問題を防ぐことができます。ここで

は、私はファイルではなく、インメモリストリームに保存していますあなたのクラスを使用した実施例であるが、原理は同じです:

#include <cereal/archives/portable_binary.hpp> 
#include <cereal/archives/json.hpp> 
#include <cereal/types/vector.hpp> 
#include <algorithm> 
#include <sstream> 

enum class myType { 
    None, unset, Type1, Type2, Type3 
}; 

class myClass 
{ 
public: 
    myClass() = default; 
    myClass(myType mt, size_t i) : isvalid(true), dtype(mt), 
           idxs(i) 
    { 
    std::iota(idxs.begin(), idxs.end(), i); 
    } 

    std::vector<size_t> idxs; 
    myType dtype; 
    bool isvalid; 

    // This method lets cereal know which data members to serialize 
    template<class Archive> 
    void serialize(Archive & archive) 
    { 
    archive(CEREAL_NVP(dtype), CEREAL_NVP(isvalid), CEREAL_NVP(idxs)); 
    } 
}; 

int main(int argc, char* argv[]) 
{ 
    std::vector<myClass> allData = {{myType::None, 3}, {myType::unset, 2}, {myType::Type3, 5}}; 

    // When dealing with binary archives, always use the std::ios::binary flag 
    // I'm using a stringstream here just to avoid writing to file 
    std::stringstream ssb(std::ios::in | std::ios::out | std::ios::binary); 
    { 
    cereal::PortableBinaryOutputArchive arb(ssb); 
    // The JSON archive is only used to print out the data for display 
    cereal::JSONOutputArchive ar(std::cout); 

    arb(allData); 
    ar(allData); 
    } 

    { 
    cereal::PortableBinaryInputArchive arb(ssb); 
    cereal::JSONOutputArchive ar(std::cout); 

    std::vector<myClass> data; 
    arb(data); 

    // Write the data out again and visually inspect 
    ar(data); 
    } 

    return 0; 
} 

その出力:

{ 
    "value0": [ 
     { 
      "dtype": 0, 
      "isvalid": true, 
      "idxs": [ 
       3, 
       4, 
       5 
      ] 
     }, 
     { 
      "dtype": 1, 
      "isvalid": true, 
      "idxs": [ 
       2, 
       3 
      ] 
     }, 
     { 
      "dtype": 4, 
      "isvalid": true, 
      "idxs": [ 
       5, 
       6, 
       7, 
       8, 
       9 
      ] 
     } 
    ] 
}{ 
    "value0": [ 
     { 
      "dtype": 0, 
      "isvalid": true, 
      "idxs": [ 
       3, 
       4, 
       5 
      ] 
     }, 
     { 
      "dtype": 1, 
      "isvalid": true, 
      "idxs": [ 
       2, 
       3 
      ] 
     }, 
     { 
      "dtype": 4, 
      "isvalid": true, 
      "idxs": [ 
       5, 
       6, 
       7, 
       8, 
       9 
      ] 
     } 
    ] 
} 
+0

std :: ios :: binaryフラグを指定しても効果がありませんでした。オペレータ>>の代わりに演算子()を使用しても、変更は行われませんでした。 私はもっと深く掘り下げて、私の例をさらに引き下げたり、同じアプリ内で読み込んだりしなければならないと思います。 – AverageCoder

+0

同じアプリケーション内でシリアライズおよびデシリアライズすることで違いはありません。それはまた失敗する。次のことは次のことです:私のallData std :: vectorは最終的に終わるもの(size AverageCoder

+0

シリアルは、ロード中にベクトルを適切にリサイズします。予約された容量では何の違いもありません。投稿した例とシリアルウェブサイトの例をもう一度見てみることをお勧めします。あなたの記述から、あなたの問題の原因となっている単純なインタフェースエラーをどこかに作っていると思います。 – Azoth

関連する問題