Question

Can you cast an object to a string of hex data (similar to how packets are sent) and then store that and then cast the object back? I know its possible with C structs which are basically objects undearneath in C++.

Compatibility of the serialization across different systems isn't important.

auto obj = new Something();

auto objHex = (unsigned char*) obj;

// store objHex in like a db
// retrieve objHex

auto obj2 = new Something();  // allocate
*obj2 = (Something*) objHex;  // set the dereference
Was it helpful?

Solution 3

Can you cast an object to a string of hex data (similar to how packets are sent) and then store that and then cast the object back?

No.
(or perhaps I do not know how.)

Note - tcp packets are not hex, or otherwise formatted, either.

Casting the pointer to your data buffer does nothing to the data, nothing to the binary contents of an array of bytes. No conversion. No formatting.

So the c-style cast to (unsigned char*) will NOT convert the contents to hex text.

If you want to translate to/from hex format, you have to write code (i.e.operator>>() and operator<<()) to translate each byte into two characters. This is easy but processor expensive. (You can find many examples on the net.)


is it possible to simply serialize C++ objects

Yes.

Many would emphasize the 'serialize' in your question, and worry about endian-ness, and other issues. 'Serialize' has specific meaning in certain contexts - persistent storage is where I first ran into these items.

If, on the other hand, binary is ok, and you just want to send a binary packet to/from the file system, or over tcp/ip socket streams, all you need to do is use write/read to store/retrieve the object's data into/out of a (binary) file, or send/receive over stream socket.

Consider the following:

 class Something
 {
 public:
    Something(void)   { clear(); }
    ~Something (void) { clear(); }

    void clear(void){for (int i=0; i<100; i+=1) m_data[i] = 0;}

    void init(void) {for (int i=0; i<100; i+=1) m_data[i] = char(i); }

    const char* data_GetAddr() { return m_data; }
    char*       data_PutAddr() { return m_data; }

    // show 3 bytes:
    void show(void) { std::cout << "m_data: "
                                << m_data[0] << "  "
                                << m_data[1] << "  "
                                << m_data[2] << "\n"
                                << std::endl;  }   
 private:
    char  m_data[100];
    // and various other POD here
 };



 int main (int, char**)
 {
    auto obj1 = new Something();
    obj1->init();
    obj1->show(); // show initialized data

    // cast does not convert from binary to text
    // so the following does not help
    // auto obj1Hex = (unsigned char*)obj1; 

    // but we can store obj1 to a file in binary
    std::stringstream ss;                        // a ram-base 'file'

    // store data to file using write.
    ss.write(obj1->data_GetAddr(), sizeof(Something));

    // now we allocate a receive buffer just as you have suggested
    auto obj2 = new Something();  // allocate space for another instance
    obj2->show();  // show this has 0's

    // retrieve obj data from file, installing it into obj2 working buffer.
    ss.read(obj2->data_PutAddr(), sizeof(Something));

    obj2->show();       // show results

    return(0);
 }

The output looks similar to the following (emacs presents the binary 0, 1, 2 as the keystrokes needed to achieve them, i.e. control-@, control-A, control-B

m_data: ^@ ^A ^B <<< obj1 after init()

m_data: ^@ ^@ ^@ <<< uninitialized obj2 (all 0's)

m_data: ^@ ^A ^B <<< obj2 after read, no init()

OTHER TIPS

No. Reasons:
a) Dynamic allocated memory, ie. pointer in the struct/class.
b) Endianess, int-size, padding etc. of the struct, order of the members...

Other things:
"If" it would be possible, there is no reason to create a full object
with constructor call before overwriting it.
And in my opinion, you´re overusing auto.

It is not easy (and not generally and automatically doable), but libraries like s11n might help.

I would consider some textual serialization format like JSON with e.g. jsoncpp, or Yaml. Of course you'll need to write some code.

As pasztorpisti commented, you might consider deriving some code from C++ declaration. Perhaps MELT might help you (you could customize g++ with it to "provide reflection info about the types of the program", per pasztopisti's words). But this would take weeks of work.

BTW, the hard issue is how to deal with pointers, notably pointers sharing the same pointed object, and pointers to code. Maybe for your particular applications things might be simpler. Read also about garbage collection and persistence; both share common concerns with your issues.

IMHO persistence and serialization is something to think very early when starting the design of your application. It probably is difficult to add afterwards.

If all you are interested in doing is serializing objects in C++ to either binary blobs of data, or to JSON, or to XML, you can take a look at a serialization library such as cereal or Boost serialization.

If you need support for raw pointers or references, Boost is the way to go. If you don't need to serialize raw pointers to things, and instead either use C++11 style smart pointers or no pointers at all, I'd recommend using cereal, as it supports pretty much everything in the standard library, whereas Boost has a more limited subset.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top