Reputation: 43
I am trying to implement a generic serialization method, that I would like to use to serialize/ de-serialize generic custom structures with the following code:
#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) ```
When using it in my main:
#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;
}
It seems to work, after my main ends I end up receiving the following error message:
free(): double free detected in tcache 2 Aborted (core dumped)
I seem unable to find the exact cause of that. After some research I understand that apparently a resource is being freed twice that has not been allocated a second time, but I am not allocating any memory on the heap anywhere at all.
Can anybody help me understand the cause of my problem, please?
Upvotes: 1
Views: 986
Reputation: 3321
One problem I can think of, is the fact that sizeof(testStruct)
is actually almost equal to the size of each element type it contains, ie:
sizeof(int) + sizeof(double) + sizeof(std::string) + sizeof(char)
The resulting size does not contain the whole actual contents of the std::string
object (which are "this is a test string"
), but instead it results to something more like the size of the primitive data types that testStruct
contains plus the size of the primitive data types that std:string
contains (which should be a pointer to the contents and not the contents themselves).
So, because you pass your testStruct
by value into the serialize
method, it should be like copying the pointer to the "this is a test string"
character sequence which is going to get freed upon destructing the contained std::string
object upon the serialize
method exit, while the same pointer is going to be freed also when the program finishes (because it is also declared in the main as the sender
's std::string
object).
You just wrapped your std::string
into the testStruct
struct (which has a destructor?), but this could probably occur if your just tested it with only a plain std::string
object as your sender
value.
It seems that this is what is happening, but I am not entirely sure, so correct me if I'm wrong in any assumption/hypothesis.
As an answer to your first comment: you cannot use a char*
for the text because this would mean that again the contents of the text would not be copied. Only the value of the actual pointer would be encoded. You could probably use a char
array of fixed size (for example say char[100]
or something) and store your text there, but that:
testStruct
.I would suggest you to have a look at the following link:
https://isocpp.org/wiki/faq/serialization
and read it a little. It might help.
If you want text representation (such as XML, or even plain custom-structured text) remember that it should again be non-portable because for example if you print a number of type int
with the value (for example) 2^30 then in another architecture where the int
is of 2 bytes size, the value would overflow. But maybe you can get around this with cstdint types (such as int_least32_t
and so on), but then you have to encode all your data into numbers, which might not seem too hard, and it probably isn't, but that includes text which would mean using a specific text encoding table, ie ASCII, UTF-8, etc...
You can also have a look at another post about serializing an object in C++.
If you want binary representation and portability and easy implementation, I would suggest to simply change your language to Java if at all possible and then have a look at the Serializable
interface and its rules. The difference with Java is that it has primitive data types of fixed size and that does not depend on the architecture, as far as I know.
If you only want to copy complex objects accross the same process, use copy constructors.
Upvotes: 1