0

void write<typename T>(const T&)T オブジェクトを ostream に書き込むという点で実装されている関数T read<typename T>()と、istream から T を読み取る一致する関数があります。私は基本的に iostreams をプレーン テキストのシリアル化形式として使用しています。これは明らかにほとんどの組み込み型でうまく機能しますが、std::strings を効果的に処理する方法はまだわかりません。

オブジェクトのシーケンスも書き出せるようにしたいと考えています。たとえばvoid write<typename T>(const std::vector<T>&)、イテレータ ベースの等価物 (ただし、実際には、常にベクトルで使用されます)。ただし、要素を繰り返し処理してそれらを書き出すオーバーロードを作成するのは簡単ですが、一致する読み取り操作で各要素がどのように区切られているかを知るのに十分な情報が追加されません。これは本質的には同じ問題です。単一の std::string を持っています。

すべての基本型と std::string で機能する単一のアプローチはありますか? それとも、数値型用と文字列用の 2 つのオーバーロードで問題を解決できるでしょうか? (おそらく、異なる区切り文字を使用するか、区切り文字エスケープメカニズムを使用して文字列を使用します。)

編集:このような質問に直面したとき、「あなたはそれをしたくない」と言って、より良いアプローチを提案するという賢明な傾向があることを理解していますが、むしろ私が尋ねたことに直接関連する提案が本当に欲しいです。代わりに私が尋ねるべきだったとあなたが信じていることよりも。:)

4

4 に答える 4

1

汎用のシリアル化フレームワークは難しく、iostreamライブラリの組み込み機能は実際にはそれを実現できません。文字列を十分に処理することさえ非常に困難です。座ってフレームワークを最初から設計し、iostream(実装の詳細になる)を無視するか、(より現実的には)既存のライブラリまたは少なくともXMLなどの既存の形式を使用することをお勧めします。

于 2010-03-24T10:57:53.750 に答える
0

文字列のエスケープを避けたい場合は、ASN.1がどのように動作するかを確認できます。文字列、基本的な型、これらのものの配列など、指定された要件に対してはやり過ぎですが、原則として、ストリームには明確な長さの情報が含まれています。したがって、何も逃げる必要はありません。

非常に単純な同等物の場合、uint32_t「ui4」の後に4バイトのデータ、int8_t「si1」の後に1バイトのデータ、IEEE floatを「f4」、IEEEdoubleを「f8」などとして出力できます。の上。配列にいくつかの追加の修飾子を使用します:「a134ui4」の後に536バイトのデータが続きます。任意の長さを終了する必要があることに注意してください。一方、次の整数のバイト数などの制限された長さは固定サイズにすることができます(ASN.1が必要以上の理由の1つは、すべてに任意の長さを使用することです)。文字列は、a<len>ui1またはのような省略形のいずれかになりますs<len>:。読者は確かに非常に単純です。

これには明らかな欠点があります。タイプのサイズと表現はプラットフォームに依存しない必要があり、出力は人間が読める形式でも、特に圧縮された形式でもありません。

算術型のバイナリ表現の代わりにASCIIを使用しますが、ほとんど人間が読める形式にすることができます(配列に注意してください:配列を出力する前に配列全体の長さを計算するか、セパレーターとターミネーターを使用することができます文字エスケープの必要がないため)、およびオプションで大きな太い人間に見えるセパレータを追加することにより、デシリアライザは無視します。たとえば、s16:hello, worlds12:||s12:hello, worldはよりもかなり読みやすいですs16:hello, worlds12:s12:hello, worlds5:hello||セパレータシーケンスのように見えるものが実際には1つではない可能性があることに注意してください。コードの途中で、5文字の文字列があると想定するようなトラップに陥らないようにする必要があります。これはの一部である可能性がありs15:hello||s5:hello||ます。

コードサイズに非常に厳しい制約がない限り、専用のシリアライザーを作成するよりも、市販の汎用シリアライザーを使用する方がおそらく簡単です。SAXで単純なXMLを読み取ることは難しくありません。とは言うものの、みんなと彼の犬は「ついに、シリアライザー/パーサー/これまでにないものを手作業でコーディングする手間を省くことができるものなら何でも」と書いていますが、大なり小なり成功しています。

于 2010-03-24T12:10:40.330 に答える
0

任意の入力ストリームからの基本型の解析を簡素化するboost::spiritの使用を検討できます。

于 2010-03-26T01:26:57.317 に答える
0

基本的に、ファイル形式を作成する必要があります。ビルトイン、文字列、およびそれらのシーケンスに制限されている場合は、空白を区切り文字として使用し、文字列をラップして記述し"(ストリーム自体の中で発生するものをエスケープし"、さらにもエスケープします)、そうでないものをすべて選択できます。 \t は、シーケンス区切り文字として組み込み型をストリーミングするために使用されます。シーケンスのサイズも保存すると役立つ場合があります。

例えば、

5 1.4 "a string containing \" and \\" { 3 "blah" "blubb" "frgl" } { 2 42 21 }

int( 5)、float( 1.4)、文字列 ( "a string containing " and \")、3 つの文字列のシーケンス ( "blah""blubb"、および"frgl")、および 2つの文字列のシーケンスint(42および)のシリアル化である可能性があります21

別の方法として、Neil が彼のコメントで示唆しているように、文字列を一連の文字として扱うこともできます。

{ 27 'a' ' ' 's' 't' 'r' 'i' 'n' 'g' ' ' 'c' 'o' 'n' 't' 'a' 'i' 'n' 'i' 'n' 'g' ' ' '"' ' ' 'a' 'n' 'd' ' ' '\' }

于 2010-03-24T11:22:20.883 に答える