Home > Mobile >  Construction vs Initialisation formal difference
Construction vs Initialisation formal difference

Time:06-26

I am learning C using the books listed here. Now I came across the following statement from C Primer:

When we allocate a block of memory, we often plan to construct objects in that memory as needed. In this case, we’d like to decouple memory allocation from object construction.

Combining initialization with allocation is usually what we want when we allocate a single object. In that case, we almost certainly know the value the object should have.

(emphasis mine)

The important thing to note here is that C primer seems to suggest that construction is the same as initialization and that they are different from allocation which makes sense to me.

Note that I've just quoted selected parts from the complete paragraph to keep the discussion concise and get my point across. You can read the complete para if you want here.


Now, I came across the following statement from class.dtor:

For an object with a non-trivial constructor, referring to any non-static member or base class of the object before the constructor begins execution results in undefined behavior. For an object with a non-trivial destructor, referring to any non-static member or base class of the object after the destructor finishes execution results in undefined behavior.

(emphasis mine)

Now does the standard specifies exactly when(at what point) the constructor execution begins?

To give you some more context consider the example:

class A {
    public:
        A(int)
        {
     
        }
};

class B : public A {
    int j;
    public:
         int f()
        {
          return 4;
        }
//------v-----------------> #2
        B() : A(f()),
//------------^-----------> #3
              j(f())
//------------^-----------> #4
        { //<---------------#5
         
        }
};
int main()
{
    B b; #1
    return 0;
}

My questions are:

  1. At what point does the derived class' constructor B::B() start executing according to the standard? Note that I know that A(f()) is undefined behavior. Does B::B() starts executing at point #1, #2, #3, #4 or #5. In other words, does the standard specifies exactly when(at what point) the constructor execution begins?

  2. Is construction and initialization the same in this given example. I mean I understand that in the member initializer list where we have j(f()), we're initializing data member j but does this initialization also implies that the construction B::B() has begun executing at point #4?

I read in a recent SO post that execution of derived ctor begins at point #4 and so that post also seem to suggest that Initialisation and construction is the same.


I read many posts before asking this question but I wasn't able to come up with an answer that is right according to the C standard.

I also read this which seems to suggest that allocation, initialization and construction are all different:

  1. Allocation
    This is the step where memory is allocated for the object.
  2. Initialization
    This is the step where the language related object properties are "set". The vTable and any other "language implementation" related operations are done.
  3. Construction
    Now that an object is allocated and initialized, the constructor is being executed. Whether the default constructor is used or not depends on how the object was created.

As you can see above, the user claims that all of the mentioned terms are different as opposed to what is suggested by C primer. So which claim is correct here according to the standard, C Primer(which says that construction and Initialisation is same) or the above quoted quoted answer(what says that construction and Initialisation are different).

CodePudding user response:

Initialization and construction are somewhat similar, but not the same.

For objects of class types, initialization is done by calling a constructor (there are exceptions, e.g. aggregate initialization doesn't use a constructor; and value-initialization zeros the members in before calling a constructor).

Non-class types don't have constructors, so they are initialized without them.

Your C Primer quote uses "initialization" and "construction" to refer to the same thing. It would be more correct to call it "initialization" to not limit yourself to class types, and to include other parts of initialization other than a constructor call.


does the standard specifies exactly when(at what point) the constructor execution begins?

Yes. B b; is default-initialization, which, for classes, calls the default constructor and does nothing else.

So the default-constructor B() is the first thing that's executed here.

As described here, B() calls A() after evaluating its argument f(), then initializes j after evaluating its initializer f(). Finally, it executes its own body, which is empty in your case.

Since the body is executed last, it's a common misunderstanding to think that B() itself is executed after A() and/or after initializing j.


I read in a recent SO post that execution of derived ctor begins at point #4

You should also read my comments to that post, challenging this statement.

CodePudding user response:

There is no distinction between point 1 and 2 in your example. It's the same point. An object's constructor gets invoked when the object gets instantiated, when it comes into existence. Whether it's point 1 or point 2, that's immaterial.

What you are separating out here is the allocation of the underlying memory for the object (point 1) and when the new object's constructor begins executing (point 2).

But that's a distinction without a difference. These are not two discrete events in C that somehow can be carried out as discrete, separate steps. They are indivisible, they are one and the same. You cannot allocate memory for a C object but somehow avoid constructing it. Similarly you cannot construct some object without allocating memory for it first. It's the same thing.

Now, you do have other distractions that can happen here, like employing the services of the placement-new operator (and manually invoking the object's destructor at some point later down the road). That seems to suggest that allocation is something that's separate, but its really not. The invocation of the placement new operator is, effectively, implicitly allocating the memory for the new object from the pointer you hand over to the placement new operator, then this is immediately followed by the object's construction. That's the way to think about it. So allocation construction is still an indivisible step.

Another important point to understand is that the first thing that every object's constructor does is call the constructors of all objects that it's derived from. So, from a practical aspect, the very first thing that actually happens in the shown code is that A's constructor gets called first, to construct it, then, once its construction is finished, then B's "real" construction takes place.

B() : A(f()),

That's exactly what this reads. B's constructor starts executing, and its first order of business is to call A's constructor. B does nothing else, until A's constructor finishes. So, technically, B's constructor starts executing first, then A's constructor. But, B's constructor does nothing until A's constructor handles its business.

The first thing that B's constructor does is call A's constructor. This is specified in the C standard.

B() : j(f()), A(f())

If you try to do this your compiler will yell at you.

So, to summarize: when you instantiate an object, any object, the very first thing that happens is its constructor gets called. That's it. End of story. Every possible variation here (placement new, PODs with no constructors, the additional song-and-dance routine with virtual dispatch) is all downstream of this, and can be defined as special, and specific, implementations of constructors.

  • Related