c++constructorplacement-newvptr

Initializing objects with virtual functions on pre-allocated memory without placement new operator - is that possible? If not, why


Let's say there's a simple class hierarchy, and a state object that uses the derived class;

struct base_class {
    int Value;
    base_class() { this->Value = 1; }
    virtual void Func() { printf("Base\n"); };

};

struct derived_class : base_class {
    int Value;
    derived_class() { this->Value = 2; }
    void Func() { printf("Derived\n"); }
};

struct state {
    int a,b,c;
    derived_class Object;
};

Now, let's assume that there's an allocator, that is not aware of the types and just returns 0-initialized allocated block memory of required size.

state *State = (state *)Allocate(sizeof(state));

And now, to properly initialize the vtable pointers we must construct the object. I've seen it done with placement new operator. And it does indeed seem to work.

However, I'm interested why if I construct the state object like this

*State = {};

The State is initialized perfectly, I see the values set to 1 and 2. But the _vfprt is 0. Even if I step into the constructor, the this pointer seems to have everything correctly set up, _vfprt points to the correct method and all.

But when I return from the constructor, the _vfprt fails to get copied itho the State object. Everything else is there. But the _vfprt is 0; So I'm just wondering if there's a special magical copy constructor that's invoked whenever new() operator is used. And if there is one, how can I use it.

I use this kind of initialization everywhere in my app, and honestly adding placement new everywhere just to support one small class is a pain in the butt. the {} call is much cleaner (and shorter), and it makes the allocation calls so much easier. If it's not possible to make this work, I'm ok with that. I'm just confused as to why the vtable pointer is not copied back after we return from the constructor.

If anyone could explain why this happens, that would be great. Thanks!


Solution

  • *state = {} is an assignment, not a construction. An assignment cannot change the dynamic type1 on an object. The virtual pointer only depends on the dynamic type of the object. So it is not necessary to copy the virtual pointer in an assignment.

    In an assignment, the object on the left side is supposed to be within its life time. The placement new expression starts an object's life time, an assignment does not. In the assignment *state = {}, the compiler assumes that an object already exists at the memory location pointed to by state. So the compiler assumes that the virtual pointer has already been initialized. The placement new will construct the object, which initializes the virtual pointer.


    1 The type of the most derived object, here it is state.