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.