C++ instance variable default initialization [duplicate] - c++

This question already has answers here:
C++11 member initializer list vs in-class initializer?
(3 answers)
Closed 2 years ago.
If I want to assign a default value to an instance variable, which method is to be preferred?
Is there a difference?
Class Foo {
int x = 0;
};
Class Foo {
int x;
Foo() : x(0) {}
};

You may choose to setup an initialization strategy for the member variable both using designated member initializers as well as member initializer list in constructors. If a given constructor does not initialize a given non-static data member, initialization of that data member will fall back on a designated member initializer, if present.
#include <iostream>
template<std::size_t TAG_N> struct Tag{};
struct Foo {
int x{42};
// ^^^^ - designated member initializer (DMI)
Foo() {} // Use DMI -> x is 42
Foo(Tag<0>) {} // Use DMI -> x is 42
Foo(Tag<1>) : x(1) {} // Initialized in mem. init list -> x is 1.
};
int main() {
std::cout << Foo{}.x << " "
<< Foo(Tag<0>{}).x << " "
<< Foo(Tag<1>{}).x << "\n";
// 42 42 1
}
Choosing which approach would enter the domain of opinion-based, but favoring consistency is never a bad advice, and [opinionated] many industry experts recommend using designed member initializers in classes which provide more than one constructor, to avoid the pitfall of e.g. adding a new member to the class but forgetting to initialize it in one the overloaded constructors' member initializer lists.

Related

Why can't a nonstatic data member be used as a default argument? [duplicate]

This question already has answers here:
Nonstatic member as a default argument of a nonstatic member function [duplicate]
(9 answers)
Closed 1 year ago.
Chapter 7.6 of the book C++ Primer says the following:
A nonstatic data member may not be used as a default argument because its value is part of the object of which it is a member. Using a nonstatic data member as a default argument provides no object from which to obtain the member’s value and so is an error.
Member functions can access class members, so why is it a problem when a default argument is used by a member function?
The short answer is: There is no a priori reason why it wouldn't be possible, but in C++ there is no mechanism to do it (at least not directly).
Default arguments are substituted at the call site. For example
void foo(int x = 42);
Then
foo();
is actually
foo(42);
With non-static members this doesn't work:
struct bar {
int y;
void moo(int x = y);
};
bar b;
b.moo(); // -> b.moo(y) ?!?
The default argument is replaced at the call site and this is not necessarily in the scope of the class. Outside of the scope of the class you need an instance to access a member.
Surely there could be rules to make it work, but instead C++ just says you cannot do it. However, you don't need it because there is a straightforward workaround:
struct bar {
int y;
void moo(int x);
void moo() { moo(y); }
};

Member variables initialization [duplicate]

This question already has answers here:
Does the default constructor initialize built-in types?
(7 answers)
What happens when you define an empty default constructor?
(2 answers)
Closed 1 year ago.
Is there any difference regarding the initialization of the x member variable in these cases:
struct A {
int x;
A() {}
};
struct B {
int x;
B() : x(0) {}
};
struct C {
int x;
C() : x() {}
};
For all these cases, in the tests I did, x is always set to the initial value of 0. Is this a guaranteed behavior? Is there any difference in these approaches?
For B::B(), x is direct-initialized as 0 explicitly in member initializer list.
For C::C(), x is value-initialized, as the result zero-initialized as 0 in member initializer list.
On the other hand, A::A() does nothing. Then for objects of type A with automatic and dynamic storage duration, x will be default-initialized to indeterminate value, i.e. not guaranteed to be 0. (Note that static and thread-local objects get zero-initialized.)

Can you initialise in the class and in the constructor and is that correct? [duplicate]

This question already has answers here:
C++11 allows in-class initialization of non-static and non-const members. What changed?
(3 answers)
Closed 2 years ago.
Considering the code below:
#include <iostream>
class tester
{
public:
tester(){}
explicit tester(double val) :
m_a(val) // I assume this now overwrites the "default" initialise value?
{}
double m_a {1.123}; // Default constructor value?
};
int main()
{
tester t1;
tester t2(2.456);
std::cout << "t1:" << t1.m_a << std::endl;
std::cout << "t2:" << t2.m_a << std::endl;
return 0;
}
My question is, can you have both the initialise value in the class and in the constructor body? - how does the compiler resolve this? It appears that the constructor wins since the output of this program is:
t1:1.123
t2:2.456
Yes, for default member initializer,
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.
In the default constructor m_a is not mentioned in member initializer list, then it will be initialized by the default member initializer as 1.123. In tester::tester(double) m_a will be initialized by the member initializer list as the argument val.

How usage of member initializer list prevents creation of redundant object in c++? [duplicate]

This question already has answers here:
Benefits of Initialization lists
(5 answers)
Closed 4 years ago.
I have a question regarding difference in initializing an object with and without constructor member initializer list.
In the following code snippet there are two classes Test1 and Test2 each with two constructors, objects of these two classes are created in the default constructor of another class Example.
Object of Test1 is created with one parameter in member initializer list, whereas that of Test2 is created with one parameter inside constructor body of Example.
class Test1 {
public:
Test1() { cout << "Test1 is created with no argument"; }
Test1(int a) { cout << "Test1 is created with 1 argument"; }
};
class Test2 {
public:
Test2() { cout << "Test2 is created with no argument"; }
Test2(int a) { cout << "Test2 is created with 1 argument"; }
};
class Example {
public:
Test1 objTest1;
Test2 objTest2;
Example() : objTest1(Test1(50))
{
objTest2 = Test2(50);
}
};
int main()
{
Example e;
}
The output of the above code is :
Test1 is created with 1 argument
Test2 is created with no argument
Test2 is created with 1 argument
My Questions
Why does object of Test2 is created twice? (The one which is created without member initializer.)
What had happened to the redundant object of Test2? Does it still occupies some memory?
How does member initializer list works in initializing class member variables?
Is there is any performance benefit in using member initializer list? (As Test1 is created only once)
Your Example constructor is (implicitly) equivalent to
Example() : objTest1(Test1(50)), objTest2()
{
objTest2 = Test2(50);
}
That is, the objTest2 object is constructed and initialized once implicitly (this is inserted by the compiler).
Then you inside the body explicitly construct and initialize a temporary Test2 object that is used to assign to objTest2.
Also note that in the initializer list objTest1(Test1(50)) constructs a temporary Test1 object, and passes it to the copy-constructor for the initialization of objTest1 (though most compilers should elide this copying). You can simplify it as plain objTest1(50).

Why non-static data members of class cannot be given default values using '( )'? [duplicate]

This question already has an answer here:
Why can in-class initializers only use = or {}? [duplicate]
(1 answer)
Closed 5 years ago.
I'm just going through the basic OOP concepts in C++ and came across the following:
class A{
public:
int i(20); //line 1
};
int main()
{
int j(20);
cout<<j<<endl;
A obj;
cout<<obj.i<<endl;
}
I get the following error at line1 when compiling (tried in both gcc and MSVC++),
expected identifier before numeric constant
I know how to assign default value for a non-static member (which can be done from C++11 on wards in different ways), but I couldn't get the reason why only this kind of default value initialization is not possible as doing the same initialization (for normal variables) anywhere else is valid.
What could be the reason for such restriction?
Edited:
From the links and answer provided, it is because "it might read as function declaration in some cases. Because of this ambiguity, it is not allowed."
But consider the following case:
//global scope
struct B{
int j;
};
int B = 10;
int object(B);
This is also a similar case, where int object(B) might be understood as a function object taking B object as argument and with int return type.
I tried this in gcc and MSVC++ and object is treated as an int variable. Why it is not restricted in this case?
Using parentheses was deemed to be too confusing since it would read very similarly to a function declaration. Think about the case of a default constructor:
class A{
public:
int i(); // function declaration -- did you mean to
// use the default constructor instead?
};
There are other ways to do it though:
class A{
public:
int i = 20;
int i{20};
int i = {20};
};