[英]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 中聲明為sender
的std::string
對象)。
您剛剛將std::string
包裝到testStruct
結構中(它有一個析構函數?),但是如果您只是使用普通的std::string
object 作為您的sender
值來測試它,這可能會發生。
似乎這就是正在發生的事情,但我並不完全確定,如果我在任何假設/假設中錯了,請糾正我。
作為對您的第一條評論的回答:您不能使用char*
作為文本,因為這意味着文本的內容不會被復制。 只有實際指針的值會被編碼。 您可能可以使用固定大小的char
數組(例如char[100]
或其他內容)並將您的文本存儲在那里,但是:
testStruct
的實例不需要那么多字符,也必須分配所有字符。 我建議你看看下面的鏈接:
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.