1


Is it possible in C++ to convert an array of chars to an object like so:

char* bytes = some bytes... MyObject obj = (MyObject)(bytes); 

?
How do I have to define the cast operator?
thanks :)

4 Answers 4

9

You probably want to define a constructor for MyObject:

class MyObject { public: explicit MyObject(const char* bytes); ... }; MyObject::MyObject(const char* bytes) { // do whatever you want to initialize "MyObject" from the byte string } 

and then you can use it:

char* bytes = some bytes... MyObject obj = MyObject(bytes); // this will work MyObject obj(bytes); // so will this 
Sign up to request clarification or add additional context in comments.

4 Comments

You can also do MyObject obj = bytes;. I'd suggest using the explicit keyword on the constructor to prevent that, it can avoid some surprising bugs.
If you go this way, don't forget the rule of three (en.wikipedia.org/wiki/Rule_of_three_%28C%2B%2B_programming%29). You should add a destructor and copy assignment operator in there as well.
Yeah, explicit is a very good idea for single-parameter constructors. I've updated my answer.
Note that the constructor of std::string is not explicit and does what we expect.
3

I can see two possibilities here. If you have data that you know represents the target type, you can use a reinterpret_cast to get them treated as an object of that type:

MyObject *obj = reinterpret_cast<MyObject *>(bytes); 

If you want to create an object of the specified type in the designated memory, you use the placement new operator to construct an object at the specified address:

char *bytes = whatever; MyObject *obj = new(bytes) MyObject; 

When you're finished using the object, you don't delete it, you directly invoke the dtor:

obj->~MyObject(); 

Note that for this to work, you need to ensure that (if nothing else) bytes points to data that's aligned correctly for the destination type.

7 Comments

Yes. This will construct a new object at that location. If you have an already constructed object there (perhaps the pointer was already casted from MyObject * and you are just casting it back now?) then larsmans' answer is the way to go.
@T.E.D: No, not really. As noted in my edited answer, if you know what's there really represents an object of the specified type, you want to use a reinterpret_cast, not a static_cast.
@Jerry: I just spotted the error in my answer myself and corrected it.
Right. That could be the case either because you happen to know that some other code already constructed an object there, or because it is a POD object.
Pretty sure this is formally UB & the only defined way is to allocate a T & memcpy to it. @T.E.D. Even if trivially copyable types - the superset of PODs guaranteed to be copyable to array of char & back & retain the same value - don't in reality emit code when allocated, the Standard still demands they have a real lifetime. This presumably means the compiler must see code that says 'Create a struct T in this piece of memory', otherwise all bets are off & UB means it can emit unsafe code or optimise the attempt away. That most compilers allow arbitrary casting doesn't make it defined
|
2

If the bytestring actually represents a valid object of type MyObject, you can get a MyObject* with

reinterpret_cast<MyObject *>(bytes) 

This is very unlikely to work though, unless the char* is the result of casting a pointer to a properly constructed MyObject.

4 Comments

Isn't this UB? Doesn't it violate the strict aliasing rule?
@ThomasMcLeod char* is exempt from that rule, so only if another non-char*, non-MyObject* pointer/reference also references bytes.
Casting to char * & dereferencing the result is exempt from aliasing. There's no allowance for the opposite. But as long as the pointers aren't dereferenced in the same scope - which surely there's no reason to do - then aliasing doesn't even enter into the equation. This is the same as/follows from the rule allowing 'round trip' casting of pointers & ensuring casting A * => B * => A * preserves the same A * on both sides. If one couldn't even cast the addresses of objects without aliasing, this wouldn't be possible. Aliasing only refers to dereferenced pointers ie lvalues.
"unless the char* is the result of casting a pointer to a properly constructed MyObject" => +1. The Standard is very clear that only the 'round trip' form of reinterpret_cast between incompatible pointer types has defined results. Anything else is UB and hoping desperately that your compiler does what you think it should. The proper way to convert arbitrary bytes to some object - assuming it's is trivially copyable, as it must be - is to allocate an instance and memcpy() from the char buffer into it. Heck, good optimisers can render to the same code as a cast, but without invoking UB
-2

I like Jerry Coffin and larsman's answers, depending on wheather the location in question already has a constructed object in it or not.

There is one further wrinkle though. If the type of MyObject happens to qualify as a POD class, then it might be OK to just use a reintreprent cast on the pointer like larsman suggested, as no constructor is really required for the object.

I say "might" because it is remotely possible that your platform uses different representations for char * and class pointers. Most I've used don't do that though.

3 Comments

Shouldn't this have been a comment on one of those answers? Anyway, address types don't matter: the cast will convert as needed. The issues is whether the Standard allows reinterpreting arbitrary bytes (address-converted) as some object type T, possibly with a stricter alignment than char that the compiler can't verify. I'm quite convinced it does not allow this - unless the char * in question originally came from a valid allocated T * - and that anything else is formally UB. See this comment: stackoverflow.com/questions/5436092/…
(copying comment for posterity) Even if trivially copyable types - the superset of PODs that qualify per the Standard to be copyable to array of char & back & keep the same value - don't in reality emit any constructor code, the Standard still demands that such objects have a well-defined lifetime. This presumably means the compiler must see code saying 'Create a struct T in this piece of memory', otherwise all bets are off & means it can emit unsafe code or optimise the attempt away. That most compilers allow arbitrary casting, as you very vaguely recommend here, doesn't make it not UB.
It would have had to be a comment on all three of them (which this software doesn't allow for really), plus I had some additional material addressing the question directly. I'll admit the current standard is much better about this than the pre-C++11 standard I was operating under when I composed this post.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.