Question

From reading this post, it is clear that placement news in c++ are used to call a class constructor on a pre-allocated memory location.

In the case that the memory is already initialized, is a placement new or a reinterpret_cast more appropriate?

For example, let's say I read a raw stream of bytes representing a framed message from a TCP socket. I put this stream into a framesync and retrieve a buffer of a known size that represents my class, which I'll call Message. I know of two ways to proceed.

  1. Create a constructor that takes a flag telling the class not to initialize. Do a placement new on the buffer passing the "don't initialize" flag.

    Message::Message( bool initialize ) 
    {
        //
        // Initialize if requested
        //
        if( initialize )
        {
            Reset( );
        }
    }
    
    void Message::Reset( void )
    {
       m_member1 = 1;
       m_member2 = 2;
    }
    
    Message* message = new ( buffer ) Message( false );
    
  2. Use a reinterpret_cast

    Message* message = reinterpret_cast< Message* > ( buffer ); 
    

I believe that both of these will produce an identical result. Is one preferred over the other as more correct, more OO, safer, easier to read, or better style?

Was it helpful?

Solution

The only meaningful rule is this:

If an instance of some type T has already been constructed at address a, then reinterpret_cast<T*>(a) to get a pointer to the object that already exists.

If an instance of some type T has not yet been constructed at address a, then use placement new to construct an instance of type T at addres a.

They are completely different operations.

The question you need to ask is very, very simple: "does the object already exist?" If yes, you can access it (via a cast). If no, then you need to construct it (via placement new)

The two operations have nothing to do with each others.

It's not a question of which one you should prefer, because they do different things. You should prefer the one which does what you want.

OTHER TIPS

I would say neither.

Using placement new and having a special method of construction seems like a hack. For one thing the standard says that, for example, an int class member that's not initialized has 'indeterminate value' and accessing it 'may' result in undefined behavior. It's not specified that the int will assume the value of the unmodified underlying bytes interpreted as an int. I don't think that there's anything that prevents a conforming implementation from zero initializing the memory before calling the constructor.

For this use of reinterpret_cast to be well defined you have to jump through some hoops, and even then using the resulting object will probably violate strict aliasing rules.

More practically, if you directly send the implementation-specified representation of a class across the network you'll be relying on the the communicating systems having compatible layouts (compatible representations, alignment, etc.).

Instead you should do real serialization and deserialization, for example by using memcpy() and ntoh() to get the data from the buffer into the members of an existing object.

struct Message {
    uint32_t m_member1;
    uint16_t m_member2;
};

extern char *buffer;

Message m;

memcpy(&m.m_member1, buffer, sizeof m.m_member1);
m.m_member1 = ntohl(m.m_member1);
buffer += sizeof m.m_member1;

memcpy(&m.m_member2, buffer, sizeof m.m_member2);
m.m_member2 = ntohs(m.m_member2);
buffer += sizeof m.m_member2;

If you don't just use a preexisting library you'll probably want to wrap this stuff up in a framework of your own.

This way you don't have to deal with alignment issues, the network representation is well defined and can be passed between differing implementations, and the program doesn't use technically undefined behavior.

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