簡體   English   中英

將通用對象序列化/反序列化為字符串

[英]Serializing/ deserializing generic objects to string

我正在嘗試實現一個通用序列化方法,我想用以下代碼序列化/反序列化通用自定義結構:

#include <string>
#include <iostream>

class MessageSerializer
{
public: 
    MessageSerializer(){}

    ~MessageSerializer(){}

    template <typename Data>
    std::string serialize(const Data data)
    {
        const char* lpData = reinterpret_cast<const char*>(&data);
        std::string serializedData( lpData, sizeof(data));
        return serializedData;
    } 

    template <typename Data> 
    void deSerialize( const std::string &serializedData, Data &deserializedObject )
    {
        const size_t serializedDataSize = serializedData.size();
        const size_t outputDataSize = sizeof(Data);

        if ( serializedDataSize != outputDataSize ){
            std::cout << "Failed size check" << std::endl; 
        }

        std::copy(std::begin(serializedData), std::end(serializedData), reinterpret_cast<char*>(&deserializedObject));
    }
};

#pragma pack(push, 1)
struct testStruct 
{
    testStruct(int a, double f, std::string text, char c) : _a(a), _f(f), _text(text), _c(c){}
    testStruct(){}

    int _a; 
    double _f; 
    std::string _text;
    char _c;
};
#pragma pack(pop) ```

在我的主要使用它時:



    #include "serializer.hpp"
#include <iostream>
#include <string>

int main ()
{
    MessageSerializer ser;
    testStruct sender(1, 345.234, "this is a test string", 'h'); 

    testStruct receiver; 
    std::string msg = ser.serialize(sender);
    std::cout <<"serialized: " << msg << std::endl; 

    std::cout << "-------------" << std::endl;

    ser.deSerialize(msg, receiver);
    
    std::cout << "received content: \na= " << receiver._a 
                << "\nf: " << receiver._f 
                << "\ntext: " << receiver._text 
                << "\nc: " << receiver._c << std::endl;
    return 0; 
}

它似乎有效,在我的主要結束后,我最終收到以下錯誤消息:

free():在 tcache 2 Aborted 中檢測到雙重空閑(核心轉儲)

我似乎無法找到確切的原因。 經過一些研究,我了解到顯然一個資源被釋放了兩次,而沒有第二次分配,但我根本沒有在堆上的任何地方分配任何 memory。

有人可以幫我理解我的問題的原因嗎?

我能想到的一個問題是sizeof(testStruct)實際上幾乎等於它包含的每個元素類型的大小,即:

sizeof(int) + sizeof(double) + sizeof(std::string) + sizeof(char)

結果大小不包含std::string object 的全部實際內容(它們是"this is a test string" ),但它的結果更像是testStruct包含的原始數據類型的大小加上大小std:string包含的原始數據類型(應該是指向內容的指針,而不是內容本身)。

因此,因為您將testStruct按值傳遞給serialize方法,所以它應該像將指針復制到"this is a test string"字符序列,該序列將在serialize時破壞包含的std::string object 時釋放方法退出,而相同的指針也將在程序完成時被釋放(因為它也在 main 中聲明為senderstd::string對象)。

您剛剛將std::string包裝到testStruct結構中(它有一個析構函數?),但是如果您只是使用普通的std::string object 作為您的sender值來測試它,這可能會發生。

似乎這就是正在發生的事情,但我並不完全確定,如果我在任何假設/假設中錯了,請糾正我。

編輯1:

作為對您的第一條評論的回答:您不能使用char*作為文本,因為這意味着文本的內容不會被復制。 只有實際指針的值會被編碼。 您可能可以使用固定大小的char數組(例如char[100]或其他內容)並將您的文本存儲在那里,但是:

  1. 引入了必須知道要存儲的最大字符數到底是多少的問題,並且即使testStruct的實例不需要那么多字符,也必須分配所有字符。
  2. 不會改變二進制表示不可移植的事實,因為每個原始數據類型的大小在不同的體系結構中是不同的。

我建議你看看下面的鏈接:
https://isocpp.org/wiki/faq/serialization
並閱讀一下。 它可能會有所幫助。

如果您想要文本表示(例如 XML,甚至是普通的自定義結構化文本),請記住它應該再次是不可移植的,因為例如,如果您打印一個int類型的數字,其值(例如)2^30 然后在如果int的大小為 2 字節,則該值會溢出。 但是也許您可以使用cstdint類型(例如int_least32_t等)來解決這個問題,但是您必須將所有數據編碼為數字,這可能看起來不太難,而且可能不是,但這包括文本意味着使用特定的文本編碼表,即 ASCII、UTF-8 等...

您還可以查看有關在 C++ 中序列化 object 的另一篇文章

如果您想要二進制表示和可移植性以及易於實現,我建議盡可能將您的語言更改為 Java,然后查看Serializable接口及其規則。 據我所知,與 Java 的區別在於它具有固定大小的原始數據類型並且不依賴於架構。

如果您只想在同一進程中復制復雜對象,請使用復制構造函數。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM