Why Must Const Members Be Initialized in the Constructor Initializer Rather Than in Its Body

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

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.

The constructor initializer list and const variable

Basically when data members are declared constant they have to have some value before the object is constructed Hence we use member initializer so that before the object is constructed the data member has some value.

in this program till the end the data member will have the same value

for real scenario:

For example you have to make a payroll program in which each employee has a first name and last name so you wouldn't want functions to accidentally modify their names so hence to prevent this you can keep them constant.

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

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?

Why can const members be modified in a constructor?

This is not modification (or assignment) but initialization. e.g.

struct Bar {
const int b = 5; // initialization (via default member initializer)
Bar(int c)
:b(c) // initialization (via member initializer list)
{
b = c; // assignment; which is not allowed
}
};

The const data member can't be modified or assigned but it could (and need to) be initialized via member initializer list or default member initializer.

If both default member initializer and member initializer are provided on the same data member, the default member initializer will be ignored. That's why b->b is initialized with value 2.

If a member has a default member initializer and also appears in the member initialization list in a constructor, the default member initializer is ignored.

On the other hand, the default member initializer takes effect only when the data member is not specified in the member initializer list. e.g.

struct Bar {
const int b = 5; // default member initialization
Bar(int c):b(c) {} // b is initialized with c
Bar() {} // b is initialized with 5
};

Why is a constructor necessary in a const member struct?

From §8.5 [dcl.init]/7:

If a program calls for the default initialization of an object of a const-qualified type T, T shall be a class type with a user-provided default constructor.

The default constructor of AClass default-initializes the const member (see below), so that member must have a user-provided default constructor. Using = default does not result in a user-provided default constructor, as can be seen in §8.4.2 [dcl.fct.def.default]/4:

A function is user-provided if it is user-declared and not explicitly defaulted or
deleted on its first declaration.


The member is default-initialized per §12.6.2 [class.base.init]/8:

In a non-delegating constructor, if a given non-static data member or base class is not designated by a mem-initializer-id (including the case where there is no mem-initializer-list because the constructor has no ctor-initializer) and the entity is not a virtual base class of an abstract class (10.4), then

— if the entity is a non-static data member that has a brace-or-equal-initializer , the entity is initialized as specified in 8.5;

— otherwise, if the entity is an anonymous union or a variant member (9.5), no initialization is performed;

otherwise, the entity is default-initialized (8.5).

C++ class const member intialization within constructor body

Collect all the calculation into a static calculation function.

struct Class {
static int calcValue(int value) {
if (Function1(value) {
Function2(&value);
return value;
}
return value * 2;
}

Class(int val)
: value(calcValue(val))
{}
};

Initialize const member variables

If you can afford a C++11 compiler, consider delegating constructors:

class Foo
{
// ...
bool const bar;
bool const baz;
Foo(void const*);
// ...
Foo(my_struct const* s); // Possibly private
};

Foo::Foo(void const* ptr)
: Foo{complex_method(ptr)}
{
}

// ...

Foo::Foo(my_struct const* s)
: bar{calculate_bar(s)}
, baz{calculate_baz(s)}
{
}

As a general advice, be careful declaring your data members as const, because this makes your class impossible to copy-assign and move-assign. If your class is supposed to be used with value semantics, those operations become desirable. If that's not the case, you can disregard this note.

Initializing C++ const fields after the constructor

You could cast away the constness in the constructor:

class Image {
public:
const int width,height;
Image(const char *filename) : width(0), height(0) {
MetaData md(readDataFromFile(filename));

int* widthModifier = const_cast<int*>(&width);
int* heightModifier = const_cast<int*>(&height);
cout << "Initial width " << width << "\n";
cout << "Initial height " << height << "\n";
*widthModifier = md.GetWidth();
*heightModifier = md.GetHeight();
cout << "After const to the cleaners " << width << "\n";
cout << "After const to the cleaners " << height << "\n";
}
};

That would achieve what you want to do but I must say I personally would stay away from that because it causes undefined behavior according to the standard (excerpt from cppreference)

const_cast makes it possible to form a reference or pointer to
non-const type that is actually referring to a const object ...
Modifying a const object through a non-const
access path ... results in undefined behavior.

I would fear any public data members(at least in regarding your particular example). I would go with Georg's approach or make the data private and provide only the getter.

How to initialize const member variable in a class?

The const variable specifies whether a variable is modifiable or not. The constant value assigned will be used each time the variable is referenced. The value assigned cannot be modified during program execution.

Bjarne Stroustrup's explanation sums it up briefly:

A class is typically declared in a header file and a header file is typically included into many translation units. However, to avoid complicated linker rules, C++ requires that every object has a unique definition. That rule would be broken if C++ allowed in-class definition of entities that needed to be stored in memory as objects.

A const variable has to be declared within the class, but it cannot be defined in it. We need to define the const variable outside the class.

T1() : t( 100 ){}

Here the assignment t = 100 happens in initializer list, much before the class initilization occurs.

Initializing fields in constructor - initializer list vs constructor body

They are not the same if member1 and member2 are non-POD (i.e. non-Plain Old Data) types:

public : Thing(int _foo, int _bar){
member1 = _foo;
member2 = _bar;
}

is equivalent to

public : Thing(int _foo, int _bar) : member1(), member2(){
member1 = _foo;
member2 = _bar;
}

because they will be initialized before the constructor body starts executing, so basically twice the work is done. That also means, if the type of these members don't have default constructor, then your code will not compile.



Related Topics



Leave a reply



Submit