aiao
aiao

Reputation: 4761

pointing to a member that has not yet been initialized

I have asked this question. My question now is how this works? To elaborate, how can I point to an object that is not yet initialised. I have made this MWE and it shows that the object is copy created not copy assigned .i.e. the object is not yet initialised yet I am able to point to it.

#include <iostream>

class Foo {
public:
    int x;

    Foo(const Foo& ori_foo) {
        std::cout << "constructor" << std::endl;
        x = ori_foo.x;
    }

    Foo& operator = (const Foo& ori_foo) {
        std::cout << "operator =" << std::endl;
        x = ori_foo.x;
        return *this;
    }

    Foo(int new_x) {
        x = new_x;
    }
};

class BarParent {
public:
    Foo *p_foo;

    BarParent(Foo* new_p_foo) : p_foo(new_p_foo)
    {
       std::cout << (*new_p_foo).x << std::endl;
    }
};

class BarChild : public BarParent {
public:
    Foo foo;

    BarChild(Foo new_foo)
        :BarParent(&foo) //pointer to member not yet initialised
        ,foo(new_foo) // order of initilization POINT OF INTEREST
        {}
};

int main()  {
    Foo foo(101);

    BarChild bar(foo);

    std::cout << bar.p_foo->x << std::endl;
std::cout << bar.foo.x << std::endl;
}

Output:

constructor
0
constructor
101
101

Do not be afraid of getting into details of how the memory is handled. And, where every member resides.

Upvotes: 2

Views: 427

Answers (2)

tletnes
tletnes

Reputation: 1998

Don't mistake Initialization for Allocation. BarChild::foo will be allocated before the constructor is called since it is stored in place, so there will be a well defined location for BarParent::p_foo to point at. Foo's constructor will Initialize BarChild::foo, but as long as you don't try to read from BarChild::foo before the constructor is called you will not notice the ordering.

Upvotes: 5

Jonathan Wakely
Jonathan Wakely

Reputation: 171263

At this line

BarChild bar(foo);

the compiler reserves enough stack space for a BarChild object then calls the constructor to begin the object's lifetime. Within the object the foo member has a fixed offset, every BarChild object has a foo member at the same offset within it, so since the this pointer has a known address within the constructor (it's the address of bar on the stack) then this->foo is also at a known address, even if the memory at that address hasn't been initialized yet. The BarChild obejct doesn't "grow bigger" as each member is initialized, its size is fixed and space for all the members is already "reserved" before they're initialized.

This is somewhat analogous to:

 char raw_memory[sizeof(Foo)];  // define block of uninitialized memory
 char* addr = raw_memory;       // take address of uninitialized memory
 new (raw_memory) Foo;          // initialize memory

The object doesn't exist yet, and it's not valid to use it, but its address is known in advance of it being initialized.

Upvotes: 3

Related Questions