Use of constructor in C++ - c++

This is very trivial question regarding the use of a constructor in C++. I will present in the form of an interview dialogue (it was difficult to present it in any other forms)
interviewer - what is a constructor?
me - constructor are special functions which makes sure that all objects are initialized before their use.
interviewer - what is an initializer list?
me - that is a list where all the initialization happens. A constructor's body is entered only after all the data members are initialized, or some constructor of all the member objects are called.
interviewer - that means initialization is carried out in initializer list, not inside constructor. But you said constructor initialize the object! Didn't you? Do you want to answer my first question.
me - I think constructor does assignment, it calls assignment operator on already initialized member objects.
So my question to you can be
how initializer list works?
what lies between function's starting address & starting braces [{]?
or just answer me how to convince my interviewer.

Technically speaking, your interpretation is accurate. No members may be initialised from inside the ctor body; only in the ctor-initializer. Any member access in the ctor body may only be assignment.
All members are "initialised" before the ctor body is entered.
However, speaking more broadly, since the body always follows the initializer, it's said that — as a unit — the object is initialised once the constructor has ended... including the body.
Partly this is because, again speaking broadly, you might consider initialisation to include some business logic that you must perform in your ctor body, even though this is not the same as actual initialisation of a data member.

You're overthinking it and allowing the interviewer to confuse you.
Initializing the members of an object is not the same thing as initializing the object itself. Just because the members have sane values doesn't mean the object has been constructed. Until the constructor has completed, the object itself has not been properly initialized.

The main things about an initialisation list are efficiency and code readability.
The readability part is self-explanatory, because you know exactly where to look to see where the values are initialised. The efficiency saving comes in the fact that if you assign them values within the code of the constructor instead, then they will be assigned twice: firstly when the object is created they will be assigned the values provided by that datatype's default constructor, then they will be assigned a new value within your object's constructor. The initialisation list just insures that they are initialised with the value you specified to begin with.
for example, here is an example of an initialisation list I used in a Doubly Linked List implementation:
template <typename T>
LinkedList<T>::LinkedList()
: size(0)
, pHead(NULL)
, pTail(NULL)
{
}
Whereas the less efficient version where size, pHead and pTail get assigned twice is shown below:
template <typename T>
LinkedList<T>::LinkedList()
{
size = 0;
pHead = NULL;
pTail = NULL;
}

Essentially, you are correct but the member initializer shouldn't be considered separate from the constructor. The initializer is a part of the constructor and is called before the main body of the constructor.
When you declare an automatic variable of a built-in type, it is both a definition and a declaration. It's a declaration because an identifier is bound to a type and it's a definition because the compiler allocates storage for it.
int var1; // declares/defines var of type int
int var2 = 0; // declares/defines a var of type int and initializes it to 0
An initializer sets the variable with an initial value when it is defined but it's considered defined before the initializer.
int x = 5;
int y = 5;
int main()
{
int x = x; // x is undefined here not 5 because x refers to itself
int y[y];
int size = sizeof(y)/sizeof(int); // size is 5 (y[5]) since y isn't defined until after the enclosing bracket so y referred to the global y in the declaration.
}
There are some variables that must be initialized however. Constants and references.
It is the same with constructors. The point at which the members have been defined is right before the ctor body. This is the order that members and bases are defined when the constructor is called.
virtual base classes
base class
members--in the order in which they were declared
ctor body is executed
After leaving the constructor body, everything has been initialized.
If you don't use the initializer, then you can assume that its already defined when entering the ctor body but you can't assume it has any particular value. Again, constants and references must be initialized in the member initializer.

The initializer list is part of the constructor. Each constructor has its own.

Related

What happens when you define an empty default constructor?

I have searched previous questions, and have not found a satisfying answer to my question:
If I define an empty default constructor for a class, as for example
class my_class{
public:
myclass(){}
private:
int a;
int* b;
std::vector<int> c;
}
my understanding is that if I define an object using the default constructor, say
my_class my_object;
then my_object.a will be a random value, the pointer my_object.b will also be a random value, however the vector c will be a well-behaved, empty vector.
In other words, the default constructor of c is called while the default constructors of a and b is not. Am I understanding this correctly? What is the reason for this?
Thank you!
a and b have non-class types, meaning that they have no constructors at all. Otherwise, your description is correct: my_object.a and my_object.b will have indeterminate values, while my_object.c will be properly constructed.
As for why... by writing a user-defined constructor and not mentioning a and b in the initializer list (and not using C++11 in-class member initializers) you explicitly asked the compiler to leave these members uninitialized.
Note that if your class did not have a user-defined constructor, you'd be able to control the initial values of my_object.a and my_object.b from outside, by specifying initializers at the point of object declaration
my_class my_object1;
// Garbage in `my_object1.a` and `my_object1.b`
my_class my_object2{};
// Zero in `my_object2.a` and null pointer in `my_object2.b`
But when you wrote your own default constructor, you effectively told the compiler that you want to "override" this initialization behavior and do everything yourself.
Since a and b are not objects but primitive datatypes, there is no constructor to call. In contrast, c is an object, so its default constructor is called.

Can constructor do any hard job other than passing values to members?

So to summarize initialization in C++ , constructor can
initialize primitive types to garbage values in memory
call default constructors on members automatically
initialize member objects with nontrivial constructors in init list
but it cannot init array properly. Ref:
C++: constructor initializer for arrays
My question is: how can I do meaningful initialization in the function body? Before entering the braces, everything has already been initialized in one way or another. The braces only contain cleaning up work, things like cout<<"This object is constructed!"
. Ref:
Use of constructor in C++
What if I want to preprocess parameter before passing it to the constructor of member object? For example:
class Foo{
public:
int x;
Foo(int y){
x = y;
}
};
class Bar{
public:
Foo foo1;
Bar(int y){
int z = superComplicatedOperation(y);
// and all other heavylifting work
foo1 = A(z);
}
};
The code above does not compile because compiler tries to init foo1 before entering the braces in constructor.
I have seen suggestions on solving this problem by providing a default constructor to Foo. So the constructor of Bar will first init foo1 to garbage value, and then assign foo1 to something meaningful in the ctor body. This is also the solution to array initialization in the quoted thread. But isn't "initializing to garbage value" an oxymoron? If the compiler wants me to do that, then it wouldn't complain about having no default ctor.
In a word, ctor is supposed to init the object in a user defined way, but I don't see any way to do a nontrivial init. Am I missing something here?
================================================================================
Clarifications: I am askingI am well aware of the Bar(int y): foo(superComplicatedOperation(y)) syntax. My question is on how to do it nicely. From a design point of view, I believe that codes in superComplicatedOperation() really should belong to the ctors. For example, say Bar takes 2 parameters (int x,int y) to initialize. We can imagine they are xy coordinates on plane. Foo also takes coordinates, but with a different reference frame. Then I need
Bar(int x,int y):foo(f1(a,b),f2(a,b))
And this kind of things quickly get ugly if ctor has a handful of params. Besides, init list looks crowded.
And if ctor body "touches" member objects, it means init list does not set members to a desired state, but rather some default zero-like states(e.g. empty vector). Therefore when calling ctor, first memory for the Bar is allocated, then members objects(subchunks of memory) go through the phases:
garbage value/uninitialized
--- init list or default member ctor --->
default "zero-like" state
--- ctor body -------------------------->
actually desired initial state
So initialization is supposed to be a two step process?
Preprocessing a parameter is fairly trivial:
class Bar
{
Foo foo;
Bar(int y) : foo(superComplicatedOperation(y)) {}
}
or you can use a C++11 delegating constructor:
class Bar
{
Foo foo;
Bar (SuperComplicatedData z) : foo(z) {}
Bar (int y) : Bar(superComplicatedOperation(y)) {}
}
What can you do in a constructor function body? Lots of things: fill containers, configure member objects, set up member object relationships, etc.
[...] constructor can
initialize primitive types to garbage values in memory
call default constructors on members automatically
This is default-initialization, which applies to every member that's not specified in the initializer list and do not have an initializer in the class definition.
initialize member objects with nontrivial constructors in init list
The member initializer list can also initialize primitive members.
but it cannot init array properly. Ref:
C++: constructor initializer for arrays
One of the answers there noted that this can now be done in C++11.
My question is: how can I do meaningful initialization in the function
body? Before entering the braces, everything has already been
initialized in one way or another. The braces only contain cleaning up
work, things like cout<<"This object is constructed!" . Ref:
Use of constructor in C++
Um...no. Frequently there's substantial logic in the constructor body proper. It's definitely not only for "cleaning up". It is true that at the time you enter the constructor body every member is initialized in some way (which may include "not initialized at all" for primitive types), but nothing says you can't assign to them or otherwise modify them. Sometimes you have to if there's some sort of circular dependencies. Sometimes the code to compute the stored value is long enough that it's far more readable inside the constructor body.
The code above does not compile because compiler tries to init foo1
before entering the braces in constructor.
I have seen suggestions on solving this problem by providing a default
constructor to Foo.
Well, you can do : foo1(A(superComplicatedOperation(y)) in your example.
So the constructor of Bar will first init foo1 to
garbage value, and then assign foo1 to something meaningful in the
ctor body. This is also the solution to array initialization in the
quoted thread. But isn't "initializing to garbage value" an oxymoron?
If the compiler wants me to do that, then it wouldn't complain about
having no default ctor.
A default ctor means that a object constructed with it is a valid object. A default ctor doesn't necessarily leave members uninitialized (or "initialized to garbage values"). Consider the default ctor for a std::vector, it had better set its internal state to something that represents an empty vector!
More fundamentally, the job of constructors (default or not) is to establish the object's invariants upon which the functions that operate on the object depend. Some objects may have no invariants, but many do (for instance, vector's internal pointer had better be either a valid pointer or null). If you have no default constructor, the compiler has no way of creating a valid object when no argument is supplied; it can't just give you something "initialized to garbage value", because it has no way of knowing whether that can in fact be a valid object of that type.
You can use an initializer list, as you should for any member variables you need to initialize.
You may prefer to initialize things to sane values and then have a function that can set the values later. It's not as clean, but if you plan to construct many objects and you can precompute the value for many of them at once it may save you some time rather than calculating the values for each object.
#include <iostream>
int superComplicatedOperation(int a)
{
return a * 10;
}
class Foo
{
public:
int x;
Foo(int y)
: x(y)
{
}
};
class Bar
{
public:
Foo foo1;
Bar(int y)
: foo1(superComplicatedOperation(y))
{
}
};
int main()
{
Bar b(7);
std::cout << b.foo1.x << "\n";
return 0;
}
class Bar {
public:
Foo foo1;
Bar(int y) : foo1(superComplicatedOperation(y)) { }
};
You can use the Constructor's initialization list for this work. It passes the values to the Ctors of the members for the first creation, this prevents the creation of a garbage object.
I guess I don't understand. I wrote code in the 1990s which has a constructor with hundreds of lines of code which does all kinds of things: opens files, instantiates dozens of objects which create linked lists and arrays based on processing file data. It certainly can initialize an array properly.

Why constant data member of a class need to be initialized at the constructor?

I want to know why constant data member of a class need to be initialized at the constructor and why not somewhere else? What is the impact of doing so and not doing so?
I also see that only static constant integral data can be initialized inside the class other than that non of the data members can be initialized inside the class.
for eg:- Suppose below is my class declaration
class A{
int a; // This we can initialize at the constructor or we can set this member by calling "vSet" member function
const int b;
static const int c = 10; //This works fine
public:
A();
~A();
void vSet(int a);
int iAdd();
void vDisplay();
};
And the constructor is defined as mentioned below:-
Edited Section: As previous constructor definition example was wrong
A::A():a(1),b(9){}
Please correct me if I am wrong.
Thanks in advance.
A::A(){
a = 1;
b = 9; // Why we need to initialize this only at the constructor.
}
Is not initialization but it is Assignment.
a and b are already constructed and you assign them values in this case. The const qualifier demands that the variable not be changed after its initialization, allowing this assignment would break that contract.
This is Initialization using Member Initialization list.
A::A():a(1),b(9)
{}
You might want to have a look at this answer of mine to know the difference:
What is the difference between Initializing and Assignment inside constructor?
As for another question, regarding only static constant integral data can be initialized inside the class, please read this answer of mine which explains in greater detail:
Why I can't initialize non-const static member or static array in class?
What you're doing is not initialization. It is assignment, so b=9 will NOT even compile, because b is a const, so cannot be assigned any value to it. It should be initialized, and to do that, use member-initialization list as:
A::A() : a(1), b(9)
{ // ^^^^^^^^^^^^ this is called member-initialization list
}
In C++11, you can use in-place initialization as:
class A{
int a = 1; //C++11 only
const int b = 9; //C++11 only
static const int c = 10; //This works fine (both in C++03 and C++11)
//...
};
Because it is constant, it's value cannot be changed. Initializing anywhere else other than the constructor would mean a default initialization, followed by an assignment, which is not permitted for a constant. It would be the equivalent of doing this:
const int i; // OK
i = 42; // Error!
Note that in C++11 it is perfectly OK to do this:
struct Foo {
const int i=42;
const double x = 3.1416;
};
But this follows the same rules, i.e there is no assignment.
A const data is a data that can never be changed. It is initialized once, and then keeps the same value forever.
Because of that, you can't just assign a value to it anywhere.
The constructor, however, is where initialization goes. So here, there is an exception, and you are able to assign a value to your const data. You can do this the classical way, or as many said, as initialization list.
Now, why you can't do this in the class definition (unlike, say, Java) when the variable is not static is another problem, that I know no answer to.
When the body of your constructor is entered, all members and sub-objects are already initialized. The only thing the constructor body can do is to change them – and that is, obviously, not allowed for const members.
You can, however, use an initializer list.
You can't initialize const members outside of a constructor because, well, they're const. By definition, you can't modify them after they've been initialized, and after the object has been constructed, anything that tries to set the value is a modification.
const values are meant to be rvalues, so they cannot appear on the right part of an expression due its constness.
so, when you use this expression on the constructor's body
A::A()
{
a = 1;
b = 9; // Why we need to initialize this only at the constructor.
}
You're using the const value as a lvalue, just as Als mentioned before. The fact is that you're trying to assing a new value to a variable that isn't allowed to change it's value afther it's lifetime had begun.
The correct way to assign values to a constant data member is in the ctor initializer list, that is, BEFORE the lifetime of the member value begins (as mentioned by Nawaz):
A::A() :
a(1),
b(9)
{
}
Finally, on the C++11 standard you're allowed to initialize all data members where it was declared, just like the static const ones.

Default constructors C++

Lets say I have this class:
class X {
public:
int x;
};
I saw that if I create an instance of X locally, x will not be initialize to 0, only if I create it globally.
Does this mean that the default constructor isn't synthesized by the compiler(I doubt it) for objects created localy or it will be synthesized but not zero out x value, if this is the case why is that ?
Constructors in C++ don't generally initialize members to 0. You have to explicitly initialize members with a value.
The reason that in the global case the memory is zero, is because static memory gets initialized to zero before anything else happens to it. In your case, the implicitly generated default constructor gets called afterwards, which does not touch the memory for member X.
See also this answer from Derek: Is global memory initialized in C++?
Note, however, that default constructors for structured, non-POD members (classes and structs) do automatically get called by the default constructor. It's just the POD members that are left alone by default.
X gets a synthesised constructor, but synthesised constructors do not zero-initialise primitives.
You are combining the concept of object construction with member initialization. As a general rule, don't expect C++ to initialize primitive data members for you, you'll need to do that yourself (preferably via an initialization list after the constructor.)
This is primarily for speed, as this allows allocation without initialization, which is useful if, for instance, you will be computing the values of the data members later and overwriting any "default" values.
I've found this site a useful reference in the past: http://www.cplusplus.com/doc/tutorial/variables/
Default constructors are not aware that it should initialize your member variables. If you need to initialize x to something, you better add your own constructor to do this for you:
class X {
public:
X() : x(0) { };
int x;
};

Why must const members be initialized in the constructor initializer rather than in its body?

Why must class members declared as const be initialized in the constructor initializer list rather than in the constructor body?
What is the difference between the two?
In C++, an object is considered fully initialised when execution enters the body of the constructor.
You said:
"i wanted to know why const must be
intialized in constructor initializer
list rather than in it's body ?."
What you are missing is that initialisation happens in the initialisation list, and assignment happens in the body of the constructor. The steps in logic:
1) A const object can only be initialised.
2) An object has all of its members initialised in the initialisation list. Even if you do not explicitly initialise them there, the compiler will happily do so for you :-)
3) Therefore, putting 1) and 2) together, a member which is const can only ever have a value assigned to it at initialisation, which happens during the initialisation list.
const and reference variables must be initialized on the line they are declared.
class Something
{
private:
const int m_nValue;
public:
Something()
{
m_nValue = 5;
}
};
would produce code equivalent to;
const int nValue; // error, const vars must be assigned values immediately
nValue = 5;
Assigning const or reference member variables values in the body of the constructor is not sufficient.
C++ provides another way of initializing member variables that allows to initialize member variables when they are created rather than afterwards. This is done through use of an initialization list.
You can assign values to variables in two ways: explicitly and implicitly:
view plaincopy to clipboardprint?
int nValue = 5; // explicit assignment
double dValue(4.7); // implicit assignment
Using an initialization list is very similar to doing implicit assignments.
Remember that the member initialization list, used to initialize base and member data objects, is in the definition, not declaration of the constructor.
More on cpp-tutorial and Code Wrangler.
Because constant variables and references must be initialized at time of declaration i.e before use.
But Constructors will assign value to a varaible not initailize the variable therefore you must use initailizier list for constant and references