Why is second initialization allowed in C++11 - c++

Under C++11 it is possible to initialize class members directly upon declaration. But it is also ok to initialize them once more in the initialization list of the constructor... why?
#include <iostream>
struct MyStr
{
MyStr()
:j(0)
{
std::cout << "j is " << j << std::endl; // prints "j is 0"
}
const int j = 1;
};
int main()
{
const int i = 0;
MyStr mstr;
}
Because doing something like this is an error, understandably:
MyStr()
:j(0),
j(1)
{
}
What is different about the first example, where the data member gets initialized upon declaration and then again in the constructor's init list?

Only one initialization actually happens. It's just that you're allowed to write a "default" one in the form of the brace-or-equals initializer, but if your constructor initializer list specifies an initializer, too, that one is the only one that's used.
As a side note, as of C++14, a brace-or-equals initializer can be provided for a non-static data member of an aggregate (which cannot have constructors).

So that an individual constructor may override it.
From the original feature proposal:
It may happen that a data member will usually have a particular value, but a few specialized constructors will need to be cognizant of that value. If a constructor initializes a particular member explicitly, the constructor initialization overrides the member initializations as shown below: [..]
Remember, you can have more than one constructor.

Related

default value in struct and the constructor order

I know we can have default value for struct members. For instance, I can set default value for those members:
struct Foo {
int a = 0;
int b = 1;
int c;
}
Suppose I have another constructor for member c:
struct Foo {
int a = 0;
int b = 1;
int c;
foo(int input_c): c(input_c) {}
}
In this case, when I construct a Foo, what's the order of construction? If I do
Foo(100)
My understanding is both a and b are default constructed first then c is assigned 100, is it correct?
------------- Updates ---------------------
Part of my confusion is also the order of execution. For the default values, is it already executed before the constructors?
For instance, I can change my Foo
struct Foo {
int a = 0;
int b = 1;
int c = -1;
foo(int d) {
c += d; // Does c always started with -1?
}
}
The order initialization happens in is quite rigid, it is always the order the members are declared in.
First of all, all default in-class initializers are applied (in the order that members are declared) unless overruled by the initialization list.
Then the constructors initialization list is used and any members listed there are initialized in the order they are declared. If any of those listed members also have in-class initializers, then those don't happen and the initialization list wins and is used to initialize the members.
Then the constructor body is executed. At this point all members are already initialized, either by in-class initialization or the initializer list. But the constructor body can choose to assign new values to those initialized members.
In any case, for a given member foo it will be initialized by the in class initialization (if any) or by the initialization list (if any) or it will be default initialized. Regardless of the method used to initialize it, that initialization will always happen after another member declared before it and before another member declared after it.
For example:
struct s {
int a = 1;
int b = 42;
int c = 666;
int d;
int e;
s() : e(3), b(123) {
c = 7;
}
};
The above will always initialize a first and since it has an in-class initializer, that will be used. It's value will be 1.
b is initialized second. It has an in-class initializer, but the constructors initialization list overrules that. It will be initialized to the value 123.
Then c is initialized to the value 666.
d is uninitialized / or rather; default initialized, which for a int is the same as uninitialized, but for other types like std::string means initialized to an empty string - it depends on the type whether you have a usable value or not.
Then e is initialized to the value 3. This happens last because it is declared last. The order it is listed in in the initialization list of the constructor is irrelevant.
Then the constructor body is executed and c is assigned the value 7. So it is both initialized and subsequently assigned to - this is usually inefficient.
The object construction is now complete.
Yes, the members will be initialized in the order they are declared in the class.
So when you call Foo(100), a and b will be initialized with the default values, and then c will be initialized to 100.

Why does a user-provided default constructor lead to an uninitialized member?

Please consider the following code:
#include <iostream>
struct A{ // with implicit default constructor
int number;
};
struct B{
int number;
B(){}; // user-provided default constructor
};
int main()
{
A aa = {};
B bb = {};
std::cout << "aa.number: " << aa.number << std::endl;
std::cout << "bb.number: " << bb.number << std::endl;
}
Running the code online
results in the following output:
aa.number: 0
bb.number: 19715
Why is bb.number uninitialized?
I thought that zero initialisation is guaranteed by using ={} ?
I thought that zero initialisation is guaranteed by using ={} ?
That is only true if the type is "correct", which B is not. B bb = {}; will default construct a B and your default constructor, B(){};, doesn't initialize number so no matter what, number will never be initialized because that is how your default constructor works. If you had a "correct" constructor like
B() : number(0) {};
// or use
int number = 0;
B(){};
Then you'd get zero initialization of number when it is default constructed.
This isn't the case with A because A is an aggregate and those come with certain guarantees like zero initialization if an empty braced-init-list, technical name for the {}, is used.
A is an aggregate type, because it doesn't have any user-provided constructors (and fulfills a few other requirements).
Therefore A aa = {}; does not call the implicitly generated default constructor. Instead initialization with brace-enclosed initializer lists performs aggregate initialization, which for an empty list means that the members are initialized as if by a {} initializer, which in turn means for a member of scalar type such as int that it will be initialized to zero.
B is not an aggregate type, because it does have a user-provided constructor.
Therefore B bb = {}; cannot do aggregate initialization and will call the default constructor instead. The default constructor (in either A or B) does not specify an initializer for the members and so the member is default-initialized, which for a fundamental type, such as int, means that it will not be set to any value. Its value will remain indeterminate.
Accessing the indeterminate value, which your program does, causes undefined behavior.
If you declare a constructor yourself, then it becomes that constructor's responsibility to initialize all the members appropriately. The rule that = {} or {} always initializes only holds under the assumption that a user-provided default constructor, if it exists, does the right thing in the sense that it provides sensible initializers to all its members and it doesn't have to mean zero-initialization necessarily.
struct B has a user-provided constructor, so it doesn't get the default constructor that can initialize the members to zero. Your user-provided constructor replaces that, so you have to do the work yourself.

How do I make user defined empty default constructor behave like compiler defined empty constructor

I've been trying to learn C++ for about a month and it still puzzles me. For example this 'easy' code:
class A
{
int m;
public:
A() = default;
int getM() { return m; }
};
class B
{
int m;
public:
// empty body and empty initializer list
B() {} // isn't this the same as "B() = default;" ?
int getM() { return m; }
};
int main()
{
A a1;
A a2{};
std::cout << "a1.m=" << a1.getM() << "\n";
std::cout << "a2.m=" << a2.getM() << "\n";
B b1;
B b2{};
std::cout << "b1.m=" << b1.getM() << "\n";
std::cout << "b2.m=" << b2.getM() << "\n";
std::cin.ignore();
}
result:
a1.m=...garbage
a2.m=0
b1.m=...garbage
b2.m=...garbage
According to CPP REFERENCE default constructor defined by the compiler does have empty body and empty initializer list. So how the heck does it (in class A) initialize member 'm' to zero when explicitly defined default constructor with empty body and empty initializer list does not. According to cppreference excerpt:
If the implicitly-declared default constructor is not defined as deleted, it is defined (that is, a function body is generated and compiled)
by the compiler if odr-used, and it has exactly the same effect as a user-defined constructor with empty body and empty initializer list.
As far as I understand it both constructors should behave exactly the same way. Seems simple yet I do not get it.
Here's the basic idea. Both A a2{}; and B b2{}; will perform what is called "value initialization" on the two objects. However, the way value initialization behaves depends on how those types are defined.
B is an object which has a user-provided default constructor. "User-provided" being the term for when you provide a body for the default constructor. Because of that, value initialization will call the default constructor. That default constructor does not initialize its members, so the members remain uninitialized.
A is an object which does not have a user-provided default constructor. Nor does it have any other user-provided constructors. And the default constructor is not deleted either. And there are no default member initializers in A. Given all of that, value initialization will perform zero initialization on the object. Which means that it will write all zeros to the memory for that object before it comes into existence.
That's what the rules say; the two do not behave the same, nor are they meant to. Nor is there anything you can do to make a user-provided default constructor act like a defaulted default constructor in all cases. You can make the user-provided constructor value initialize its members, but it would do so all the time, even if you use default initialization (B b1;, for example).
Why do the rules say that? Because = default is not supposed to be equivalent to an empty constructor body. Indeed, being different is why = default exists as a feature.
When you = default your default constructor, you are saying "generate the default constructor as you normally would". This is important, because there are things you can do which actively prevent the compiler from generating a default constructor for you. If you specify other constructors (which are not copy/move constructors), the compiler will not automatically generate one. So by using = default syntax, you're telling the compiler that you want the generated default constructor.
By contrast, if you make an empty body in your default constructor, you are saying something totally different. You are explicitly saying, "If a user calls my default constructor, I want my members to be default-initialized." That's what it means when you have an empty member initializer list in a constructor, after all. So that's what it should do.
If = default and an empty body behaved the same, there would be no way for you to get that behavior, to say that you want default initialization of your members no matter what.
Basically, Cppreference's statement is completely wrong; it does not have "exactly the same effect as a user-defined constructor with empty body and empty initializer list". Nor is it supposed to.
If you want to understand the thinking of value initialization a bit further, consider this.
int i{};
That is guaranteed to produce a value of 0 for i. It is therefore reasonable that this:
struct S{int i;};
S s{};
Should also produce a value of 0 for s.i. How does that happen? Because value initialization will zero-initialize s.
So how does a user say that they don't want that, or want some special form of initialization? You communicate that the same way you communicate everything else: you add a constructor. Specifically, a default constructor that does the form of initialization you want.
If any constructor is provided zero-initialization does not take place as stated here
Zero initialization is performed in the following situations:
...
2) As part of value-initialization sequence for non-class types and for members of value-initialized class types that have no constructors, including value initialization of elements of aggregates for which no initializers are provided.
Also here
The effects of value initialization are:
1) if T is a class type with at least one user-provided constructor of any kind, the default constructor is called;
Which makes sense. One should be able to control whether any additional operations can be added. If you provide a constructor, you take responsibility for your object initializations.

C++11 member variable of reference type, different behaviour after vector push_back

I was using somebody else's class which was acting odd when I pushed it into a vector. It involves a member variable which is a reference to another member variable. Here is the smallest self-contained example:
#include <iostream>
#include <vector>
class Myclass {
public:
Myclass() : a(1.0) {}
float a;
float &a_ref = a;
void addOne() {
a = a + 1.0;
}
};
int main() {
Myclass instance1;
instance1.addOne();
//prints 2:
std::cout << "instance.a_ref is " << instance1.a_ref << std::endl;
std::vector<Myclass> vec;
Myclass instance2;
vec.push_back(instance2);
vec.at(0).addOne();
//prints 1;
std::cout << "vec.at(0).a_ref is " << vec.at(0).a_ref << std::endl;
return 0;
}
I was compiling with g++ and -std=c++11, so I didn't notice the problem for a while. I see now the issue is probably to do with the synthesised copy constructor and the reference member. But what I'm not sure about is:
Why is there different behaviour when the object is in a vector ?
Why does g++ not give any warnings about this, using c++11 standard ?
Bonus question because I'm curious:
What is initialized first, a or a_ref?
The problem is indeed with the defaulted copy constructor. The defaulted copy constructor initialises all members from the members of the source object. That is, the defaulted copy constructor is identical to this:
Myclass(const Myclass &src) :
a(src.a),
a_ref(src.a_ref)
{}
The defaulted copy constructor initialises all members, so it ignores any in-class initialisers.
This is also why pushing into a vector causes the problem. vec.at(0) was created as a copy of instance2, which means vec.at(0).a_ref refers to instance2.a. You could easily verify this by printing their addresses (live example).
The implicitly defined copy/move constructor:
[...] performs a performs a memberwise copy/move of its bases and members. [ Note: brace-or-equal-initializers of non-static data members are ignored. [...]
In particular, reference members are direct-initialized to refer to the same object the corresponding reference member in the source object refers to.
So in your case, vec.at(0).a_ref refers to the member a of instance2.
This is not detected by the compiler because in general reference members are expected to refer to a longer-lived object outside the class.

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.