-2

シリアライズしたいこのクラスがあります:(プライベート属性)

class Task {
    public:
        enum Status { COMPLETED, PENDIENT };
        // GETTERS SETTERS... 
        // UTILS
        const std::ostream& storeTask( std::ostream &stream );
        const std::istream& retrieveTask( std::istream &stream );
private:
        void setID();
        static int sCount;
        int id;
        std::string text;
        Status status;
        tm timestamp;
};

ご覧のとおり、次のように定義したstoreTaskandretrieveTaskメソッドを実装することで、そうしようとしています。

// SERIALIZATION
const std::ostream& Task::storeTask( std::ostream &stream ) {
  stream.write((char *) &id, sizeof(int));
  stream.write((char *) text.c_str(), sizeof(text.length()));
  stream.write((char *) &status, sizeof(Status));
  stream.write((char *) &timestamp, sizeof(tm));
  return stream;
}
const std::istream& Task::retrieveTask( std::istream &stream ) {
  stream.read((char *) &id, sizeof(int));
  stream.read((char *) text.c_str(), sizeof(text.length()));
  stream.read((char *) &status, sizeof(Status));
  stream.read((char *) &timestamp, sizeof(tm));
  return stream;
}

2 つの Task オブジェクトのベクトルを作成し、それらの storeTask メソッドを使用してそれらを記述し、次に 2 つの異なる Task を含む別の Task ベクトルを作成し、Task ベクトル番号 1 の値を 2 番目のベクトルにリロードして、実装をテストしています。

両方のタスクでバイナリ ファイルを書き込むと問題なく動作するように見えますが、再度読み取ると、テキスト文字列の最初の 4 文字のみがフェッチされます。

int main() {
        std::vector<Task> myTasks;
        Task task1("First Task");
        Task task2("Second Task");
        myTasks.push_back(task1);
        myTasks.push_back(task2);

        std::vector<Task> myTasks2;
        Task task3("Task num1");
        Task task4("Task num2");
        myTasks2.push_back(task3);
        myTasks2.push_back(task4);

        writeTasks(myTasks);
        readTasks(myTasks2);

    return 0;
}

void writeTasks(std::vector<Task> aTasks) {
        std::fstream fileStream("fileStream", std::ios::out | std::ios::binary);
        for ( int x = 0; x < aTasks.size(); x++ ) {
            std::cout << "Storing: " << aTasks[x].getText() << "\n";
            aTasks[x].storeTask(fileStream);
        }
        fileStream.close();
}
void readTasks(std::vector<Task> aTasks) {
        std::fstream fileStream;
        fileStream.open("fileStream", std::ios::in | std::ios::binary);
        for ( int x = 0; x < aTasks.size(); x++ ) {
            std::cout << "Retrieving " << aTasks[x].getText();
            aTasks[x].retrieveTask(fileStream);
            std::cout << " as --> " << aTasks[x].getText() << " - " << aTasks[x].getTime() << "\n";
        }
        fileStream.close();
}

そしてそれは戻ります:

Storing: First Task
Storing: Second Task
Retrieving Task num1 as --> Firs num1 - 01:02:26
Retrieving Task num2 as --> Seco num2 - 01:02:26

いつ返すべきか:

Storing: First Task
Storing: Second Task
Retrieving Task num1 as --> First Task - 01:02:26
Retrieving Task num2 as --> Second Task - 01:02:26

何か案は?問題がバイナリのシリアライゼーションの書き込みにあるのか、読み取りにあるのかわかりません...時間や日付などの他の値は正常に機能しているようです。

Astext.c_str()が a を返すようにconst char *、文字列から char * に変換する小さな関数を宣言しました。

char * str_to_char(std::string s) {
    char *a=new char[s.size()+1];
    a[s.size()]=0;
    memcpy(a,s.c_str(),s.size());
    return a;
}

そしてretireveTaskメソッドでこれを試しました:

stream.read(str_to_char(text), text.size() + 1);

しかし得た:

Storing: First Task
Storing: Second Task
Retrieving Task num1 as --> Task num1 - 589824:524288:131072
Retrieving Task num2 as --> Task num2 - 112:09:08
4

1 に答える 1

3

2 つの大きな問題があります。

  1. 書くときは書くsizeof(text.length()))。そのsizeof演算子は、(通常は 4 または 8 バイト)std::string::size_typeによって返されるサイズを返します。text.length()のみを使用してくださいtext.length()

  2. 読むときは、文字列に直接入れられたテキストを読もうとします。実際の文字列が割り当てられていないか、十分なスペースが割り当てられていない可能性があるため、これは間違いなく機能しません。何かを読むことができて、プログラムがここでクラッシュしないのは幸運だと思います。

文字列 (または任意の可変サイズ データ) をシリアル化するには、最初に文字列の長さを格納する必要があります。これにより、後で読み取る量がわかります。

適切なシリアライゼーションは簡単ではありません。すべての奇妙さとコーナーケースを正しく処理するBoost シリアライゼーションを検討することを強くお勧めします。

于 2012-10-08T05:19:23.327 に答える