First of all, fundamentally: std::string
is a data type to hold text. Exclusively. It should not be used to hold binary data. Use a std::vector<(unsigned) char>
for that.
Secondly, you are using heap allocation without needing to:
T* pt = new T(t);
This makes no sense at all, and introduces the potential of a memory leak. You could simply make a copy – but you don’t even need to do that. Just work on the original data.
Next, about naming; it’s general convention in C++ to use underscore_separated_names rather than camelCase or PascalCase. This is only a convention but I’d follow it unless there’s a very compelling reason not to.
Also on the topic of naming: returnSize
is redundant, return
has no place in the name. Rename it to object_size
or something along those lines. You are also inconsistent in your naming convention here.
To get the size of a zero-terminated string, use std::strlen
, that’s more efficient than converting to a std::string
.
Finally, the code simply doesn’t work. It creates a bit-by-bit shallow representation. That only works for simple composite objects, it no longer works for objects that use pointers or references internally – you’ve already noticed that, because otherwise you wouldn’t need to create a special chase for char*
and std::string
. Incidentally, for the case of char*
you specialise returnSize
but for the case of std::string
you specialise Serialize
and DeSerialize
. That’s asymmetrical and means that you have several places that might require changing when new types are added. You should reduce this to a single point which requires specialisation.
Ignoring that, I’d rewrite the code as follows:
#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
typedef unsigned char byte_t;
typedef std::vector<byte_t> buffer;
std::size_t object_size(const char* s) {
return std::strlen(s);
};
template<typename T>
std::size_t object_size(T const& obj) {
return sizeof(obj);
};
template<typename T>
buffer serialize(const T& obj) {
std::size_t size = object_size(obj);
buffer buf(size);
byte_t const* obj_begin = reinterpret_cast<byte_t const*>(&obj);
std::copy(obj_begin, obj_begin + size, buf.begin());
return buf;
};
template<>
buffer serialize<std::string>(std::string const& str) {
return serialize(str.c_str());
};
template<typename T>
T deserialize(buffer const& buf) {
return *reinterpret_cast<const T*>(&buf[0]);
}
template<>
std::string deserialize<std::string>(buffer const& buf) {
return deserialize<char*>(buf);
}
int main() {
using std::cout;
int x = 97;
buffer c = serialize(x);
cout << deserialize<int>(c) << "\n";
char g = 'g';
buffer c2 = serialize(g);
cout << deserialize<char>(c2) << "\n";
std::string k = "blabla";
buffer c3 = serialize(k.c_str());
cout << deserialize<char*>(c3) << "\n";
std::string ka = "string";
buffer c4 = serialize(ka);
cout << deserialize<std::string>(c4) << "\n";
}
… but like I said, this solution doesn’t generalise and is pretty useless in practice. Have a look at Boost.Serialization for a proper implementation. Unfortunately this is quite a complex problem.