When to use which data member initialization in C++ - c++

Considering this program:
#include <iostream>
class C
{
public:
C(void): a(1)
{ a=2; }
int a{3};
};
int main(void)
{
C c{};
std::cout << c.a; // 2
}
I can see three forms of data member initialization:
using a member initializer list
using the Constructor
using a declaration in the class body
When to use which?

1: Using a declaration in the class body
You should use this when the member will always be initialized with the same value, and it doesn't make sense to have to explicitly write that for each constructor.
2: Using a member initializer list
The member initializer list is obviously necessary for a member that lacks a default constructor, but aside from that, if you're initializing a member based on the constructor, it makes sense to do it here.
3: Using the constructor body
The constructor body is more useful for logic that can't be performed in a single statement (in the init-list). However, I don't think there is much difference between initializing a POD in the member initializer list or the constructor body.

My suggestion is to use:
int a{3};
This makes sure that a is initialized to 3 no matter how many constructors you have in the class.
My second choice will be to use the member initialization list.
c(void) : a(1) {}
The third option, using code to set the value of a member variable, should be avoided.

Related

C++ Classes: Initializing attributes without constructor overloading

Coming from JavaScript and Python, I'm trying to understand the nuances and purpose around C++ class constructors.
In the example below, why is it allowed to initialize attributes without a constructor?
class MyClass {
public:
int a = 1;
int b = 2;
};
Does the default constructor include the above definitions/initializations? What is the difference to the following two examples?:
1.
class MyClass {
public:
int a;
int b;
MyClass(){
a = 1;
b = 2;
}
};
JavaScript/Python style (Is this even possible?)
class MyClass {
public:
MyClass(){
// Some kind of variable declaration and definition like:
// this.a = 1;
// this.b = 2;
}
};
To me having the option of initialization without a constructor sounds like an overkill and is confusing. In both Python and JavaScript one usually declares and initializes all variables from the constructor, and only from there only.
What is the best practice here?
In the example below, why is it allowed to initialize attributes without a constructor?
Because C++11 specifically added that feature. See Member initialization.
Does the default constructor include the above definitions/initializations?
Yes. This code:
class MyClass {
public:
int a = 1;
int b = 2;
};
Is roughly (not exactly) equivalent to this code:
class MyClass {
public:
int a;
int b;
MyClass() : a(1), b(2) {}
};
It is actually possible to use both forms of initialization at the same time, eg:
class MyClass {
public:
int a = 1;
int b = 2;
MyClass() = default;
MyClass(int a) : a(a) {}
};
Per Member initialization:
Non-static data members may be initialized in one of two ways:
In the member initializer list of the constructor.
Through a default member initializer, which is a brace or equals initializer included in the member declaration and is used if the member is omitted from the member initializer list of a constructor.
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 for that constructor.
The a member is not specified in the default constructor's member initialization list, so it will be initialized with its default value of 1 when a MyClass object is default constructed.
The a member is explicitly initialized in the converting constructor's member initialization list, so its default value of 1 will be ignored and it will instead be initialized with the caller-provided value when a MyClass object is constructed with an input value.
The b member is not specified in either constructor's member initialization list, so it will always be initialized with its default value of 2.
What is the difference to the following two examples?:
The first example is what you would have to do prior to C++11 (if you are not using the constructor's member initialization list, as shown above).
The second example is not legal in C++. You can't declare members dynamically, and certainly not from inside a constructor. They have to be declared statically in the class declaration itself.

Initializing data members inside class body

When data members should be initialized directly inside class/struct body over using constructor?
struct A{
int x;
A() : x{3} {}
};
struct B{
int x{3};
};
The above two methods have the same effect.
Member init list must be used if the value depends on a constructor argument. It must also be used if separate constructors should initialise the member with different value. It must also be used prior to C++11, because that is the language version where the default member initialisers were introduced.
Otherwise the choice is up to the programmer. Default member initialisers are useful for avoiding repetition in constructors that initialise with the same, constant value, as well as having more concise and simpler syntax.
I would like to point out one difference.
struct B{
int x{3};
};
The above initialization applies to all the constructors where x is not explicitly initialized.
The below initialization applies ONLY to the default constructor. So if you are following below approach, you may end up with lot of boiler plate code when the value initialized is same.
struct A{
int x;
A() : x{3} {}
};

Initializer list vs. initialization method

There are at least two ways to initialize a class in C++.
(1) Initializer List
struct C
{
int i;
C() : i(0) {}
};
(2) Initializer Method
struct D
{
int i;
C() { init(); }
void init() {
i = 0;
}
};
I need to re-init objects of my class from time to time. With the second solution, I can simply call obj.init(). With the first solution, I would either have to add an init() function which essentially duplicates the initializer list effect or use obj = C().
Is there a more-or-less consensus on what variant is better here? Is there a disadvantage to using an initializer method (except the possible loss of performance as mentioned in the C++ FAQ).
The main difference is that without using initialization list, members are created and then values are assigned to them. When you use initialization list, members are directly created by using given values.
One of situations, when using initialization is important, is when your class holds some references as a members and it is necessary to initialize these members right when they are being constructed:
class A
{
public:
A(B& bRef) : bRef_(bRef) { }
private:
B& bRef_;
}
This question could help you too: In this specific case, is there a difference between using a member initializer list and assigning values in a constructor?
Your init() method is perfectly fine. As you yourself have mentioned, you want to initialize these members more times than just first time when the instance of this class is being constructed, so for the sake of reusability and simplicity it's right to keep it in a method. Don't try to improve performance of your code unless you really need it.
Some people say that It's easier to make a correct program fast than it's to make a fast program correct. ;)
When creating an array (using vector, or allocating dynamically using new) you will have to explicitly call init on each of its members while using a constructor, it will automatically be called for all elements.
I prefer placing basic initialization into the constructor and more complex logic into an init method. In my opinion a constructor should not perform any complex operations.
Below are the scenarios when initializer list is used:
For initialization of non-static const data members.
For initialization of reference members.
For initialization of member objects which do not have default constructor.
For initialization of base class members.
When constructor’s parameter name is same as data member.
For Performance reasons.

Why are member variables visible in c++ constructor initialization lists?

I came across this due to a bug in my code and I'm curious why it's allowed. What reason is there that allows object members to be visible in the constructor initialization list?
#include <stdio.h>
class derived {
private:
int * value2;
public:
derived();
};
derived::derived()
: value2(value2){} // Uninitialized self-assignment
int main()
{
derived thisChild;
}
Clang gives a warning about this but unfortunately g++ does not.
So you can initalise one member using another; this is perfectly fine if the other has already been initialised, or if you're just using its address to initialise a pointer or reference. For example:
struct Thingy
{
int & r;
int a;
int b;
Thingy(int x) :
r(a), // OK - a has a valid address, and we're not using the value
a(x),
b(a) // OK - a has been initialised
{}
};
It would be rather tricky to allow that and disallow your example.
If it is not visible, you cannot write this:
A(int n) : some_num(n), another_num(some_num*10) {}
then what would be the point of member-initialization list?
As for self-initialization (uninitialized variable), you can do even this:
int xyz = xyz; //will compile
You can think of the initialization list as part of the body of the method (specifically the constructor), so it is natural that you can access the member variables of an object in one of its methods
Also, you might want to reuse an already created member variable to initialize others -- note: you will have to know the exact order of initialization (order of member variable declaration) to make sure you are using this portably
I think you mean why are member variables accessible in initializer expressions.
One reason is that the initialization of one member variable can depend on another.
That's fragile, but sometimes necessary to avoid awkward code such as artificial base classes.

Class member initialisation differences

With respect to the class definition for complex number, I saw two types of definitions:
Definition 1
class Complex
{
private:
double re;
double im;
public:
Complex(float r,float i) {re = r; im = i;}
~Complex() {};
};
Definition 2
class Complex
{
private:
double re;
double im;
public:
Complex(double r,double i): re(r), im(i) {}
~Complex() {};
};
The first definition looks OK to me but I do not quite understand the second definition, how does
Complex(double r,double i): re(r), im(i) {}
work? What does "re( )" mean?
It's called an initializer list. In a class's constructor, you can initialize member variables with this syntax. So in this, it's equivalent to putting the statements re = r; im = i; in the body of the constructor.
In the case of POD variables such as int, double, and pointer types, there is no difference between the initializer list syntax and regular assignments in the body. However, for const variables, references, and objects with non-trivial constructors, there is an important difference:
For const variables and reference variables, they must be initialized in the initializer list. They cannot be initialized by assigning to them in the body.
For objects with non-trivial constructors, how you initialize them in the initializer list corresponds to the constructor that gets called. If you omit the variable, then that object's default constructor gets called (if that object has no default constructor, then that is a compiler error).
Because of that, it's generally recommended that objects with constructors get initialized in the initializer list to avoid redundant work -- if you let its default constructor run by omitting it from the initializer list and then perform some sort of initialization in the constructor body, you're initializing it twice, which can be wasteful.
For example:
class Example
{
private:
std::string m_string;
public:
Example()
{
// m_string is first initialized by the std::string default constructor,
// then we assign to it with operator=(const char *).
// This is inefficient.
m_string = "test";
}
Example(int dummy)
: m_string("test")
{
// Better: we just call the std::string(const char*) constructor directly
}
};
The second form of the Complex constructor uses initialization lists, which are a different (and preferred way) of initialization class members.
The re(...) thing means that member field re should be constructed with whatever arguments it is passed.
As another example - you can create primitives like double and int like this:
double d(5.0d);
int i(5);
Which should explain how the parentheses work in the lists.
That's an initialization list. It sets the value of re to r and the value of im to i.
Generally you'll see a performance gain by using an initialization list, but it's also important to know when not to use it.
First of all, there should be a semicolon after the entire class definition in C++. Otherwise your code will fair to compile.
Anyway, the
Complex(double r,double i): re(r), im(i) {}
is a constructor for the Complex class that simply places the value of r into re and the value of i into im. That is another way of initializing a class's values.
Note that initialization lists like that can be very useful for initializing member classes within a class. Here's an example:
class MemberClass
{
private:
int mValue;
public:
MemberClass(int value): mValue(value) {}
};
class MemberHolder
{
private:
MemberClass mMember;
public:
MemberHolder(int value): mMember(value) {}
};
Initialization lists are important for using classes without a default constructor within other classes.
In C++ there is a distinction between assignment and initialization.
a = 5; // assignment
int b = 6; // initialization
int b(6); // also initialization
The first version of your class performs assignment inside the body of the constructor. This is more expensive, because the data members re and im are first default-constructed, and then are assigned their values.
In the second version constructor initialization list is used. Here the data members are initialized with the supplied values. This occurs in one step, while default constructor + assignment are two steps. This is more efficient.
Generally, you should prefer initializing your data members in the initialization list to assigning their values inside the body of the constructor. There is a caveat, though. The data member in the initialization list are initialized in the order in which they are declared in the class, not in the order in which they occur in the initialization list. Generally, you want the order of members in the list to match their order of declaration. Otherwise you may end up with very hard to find bugs if the initialization of one data member depends on the value of another.