Default initialization of C++ member array of objects? - c++

Suppose I have a C++ class set up as follows:
class Foo{
public:
struct Pair{
int x;
int y;
Pair(){ x = 2; y = 4; }
};
private:
Pair pairArr[16];
}
Without otherwise initializing the pairArr, what is the default value of the Pair structs inside it? Does C++ call the constructor (initializing it with x=2, y=4) or are the objects not created yet, leaving me with an array of "junk" objects until I initialize the indices myself?
I know if it is an array of a primitive data type, they are default initialized (if I had an array of ints, they would all be 0). However, I don't know if this behavior holds for more complex objects like my struct here.

Classes and structs are equivalent in c++, it's only the default access specifier that differs. So check Arrays and Classes, which says:
The normal array declaration style uses the default constructor for each object in the array (if the class has a default constructor)
From a practical point of view, do this in your struct:
Pair() : x(2), y(4) { std::cout << "Called\n"; }
and you will see the message being printed 16 times.
That's a usual approach (to add print messages to constructor to destructor) when you want to know what is called (and usually their order).
Tip: Use an initializer list, rather than assigning values inside the body of the constructor.

Related

Initializing and Constructing Arrays of Objects in C++ [duplicate]

This question already has answers here:
How do I use arrays in C++?
(5 answers)
Closed 6 years ago.
When declaring an array of objects, are all the objects constructed at initialization, or do they have to be constructed after initialization? Here is an example of what I am trying to explain:
Lets say I have this class:
class Object{
public:
int x = 4;
};
And this array:
Object objects[8];
If I was to access any of the variables within the objects, would I have to construct the objects first, or was that done in the array? So if I did this:
cout << objects[4].x;
Would it print out 4?
In C++11 your code is perfectly valid, it performs in-class initialization, and indeed, cout << objects[4].x; will print out 4. In previous C++ versions (C++98/03), the code is invalid, and you'd need a default constructor to initialize the variable x, like
class Object{
public:
int x;
Object(int x = 4): x(x){}
}
are all the objects constructed at initialization
Yes, all of elements of array will be default initialized.
if T is an array type, every element of the array is default-initialized;
And
if T is a non-POD (until C++11) class type, the constructors are considered and subjected to overload resolution against the empty argument list. The constructor selected (which is one of the default constructors) is called to provide the initial value for the new object;
And
Would it print out 4?
Yes. For class Object, the implicitly-declared default constructor will be invoked here. And the member x is not initialized by the member initializer list (in default constructor), the default member initializer is applied, then x will be initialized with value 4.

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.

Constructor initialization Vs assignment

Let us consider the following classes
class test1
{
private:
int a;
int b;
public:
test1():a(0),b(0){}
};
class test2
{
private:
int a;
int b;
public:
test2()
{
a=0;
b=0;
}
};
Now, I know that test1() constructor is the right way to initialize the data members of a class, because in test2() we are performing assignment and not initialization. My questions are:
What might go wrong if we perform assignment instead of initialization?
Doesn't the compiler internally perform assignment in case of test1() constructor? If not, then how are these initialized?
What might go wrong if we perform assignment instead of initialization?
Some class types (and also references and const objects) can't be assigned; some can't be default-initialised; some might be more expensive to default-initialise and reassign than to initialise directly.
Doesn't the compiler internally performs assignment in case of test1() constructor? If no then how are these initialized?
In the case of primitive types like int, there is little or no practical difference between the two. Default-initialisation does nothing, and direct-initialisation and assignment both do essentially the same thing.
In the case of class types, default-initialisation, assignment and direct-initialisation each call different user-defined functions, and some operations may not exist at all; so in general the two examples could have very different behaviour.
For your example there is no real different because you are initializing plain integers.
But assume these integers are objects with constructors, then the compiler would generate the following calls:
// test1
a::copy_constructor(0);
b::copy_constructor(0);
// test2
a::default_constructor();
b::default_constructor();
a::operator = (0);
b::operator = (0);
So depending on your objects test2 could have a huge performance impact. Also by initializing your objects in the initializing lists guaranties that your variables have the data when you enter the constructor. One 'drawback' of the initializer list is that the it is executed in the order that the variables are declared and not in the order of the initializer list, so it could be that you don't want to use the initializer list.
A third variant utilizing direct-list-initialization. Advantages are
variables don't have to be default-initialized in the constructor
the constructor and not the copy/move assignment operator is used to construct the members (as the other answers said, it doesn't matter for the primitive type of this example)
So this is less error-prone than both variants in the question:
#include <iostream>
class Test3
{
public: // Made public so we can easily output the vars. No struct is used to be consistent with question.
int a { 4 }; // No need for separate initialization in constructor.
int b { 2 }; // No need for separate initialization in constructor.
};
int main()
{
const auto t = std::move(Test3()); // Implicitly-declared default constructor + implicitly-declared move assignment operator
std::cout << t.a << t.b;
}
Output is 42.
Constructor-initializers allow initialization of data members at the time of their
creation.
Some programmers prefer to assign initial values in the body of the constructor. However, several data types must be initialized in a constructor-initializer. The following lines summarizes them:
const data members
You cannot legally assign a value to a const variable
after it is created. Any value must be supplied at the
time of creation.
Reference data members
References cannot exist without referring to
something.
Object data members for which there is no default constructor
C++ attempts to initialize member objects using a
default constructor. If no default constructor exists, it
cannot initialize the object.

Initialisation and assignment

What EXACTLY is the difference between INITIALIZATION and ASSIGNMENT ?
PS : If possible please give examples in C and C++ , specifically .
Actually , I was confused by these statements ...
C++ provides another way of initializing member variables that allows us to initialize member variables when they are created rather than afterwards. This is done through use of an initialization list.
Using an initialization list is very similar to doing implicit assignments.
Oh my. Initialization and assignment. Well, that's confusion for sure!
To initialize is to make ready for use. And when we're talking about a variable, that means giving the variable a first, useful value. And one way to do that is by using an assignment.
So it's pretty subtle: assignment is one way to do initialization.
Assignment works well for initializing e.g. an int, but it doesn't work well for initializing e.g. a std::string. Why? Because the std::string object contains at least one pointer to dynamically allocated memory, and
if the object has not yet been initialized, that pointer needs to be set to point at a properly allocated buffer (block of memory to hold the string contents), but
if the object has already been initialized, then an assignment may have to deallocate the old buffer and allocate a new one.
So the std::string object's assignment operator evidently has to behave in two different ways, depending on whether the object has already been initialized or not!
Of course it doesn't behave in two different ways. Instead, for a std::string object the initialization is taken care of by a constructor. You can say that a constructor's job is to take the area of memory that will represent the object, and change the arbitrary bits there to something suitable for the object type, something that represents a valid object state.
That initialization from raw memory should ideally be done once for each object, before any other operations on the object.
And the C++ rules effectively guarantee that. At least as long as you don't use very low level facilities. One might call that the C++ construction guarantee.
So, this means that when you do
std::string s( "one" );
then you're doing simple construction from raw memory, but when you do
std::string s;
s = "two";
then you're first constructing s (with an object state representing an empty string), and then assigning to this already initialized s.
And that, finally, allows me to answer your question. From the point of view of language independent programming the first useful value is presumably the one that's assigned, and so in this view one thinks of the assignment as initialization. Yet, at the C++ technical level initialization has already been done, by a call of std::string's default constructor, so at this level one thinks of the declaration as initialization, and the assignment as just a later change of value.
So, especially the term "initialization" depends on the context!
Simply apply some common sense to sort out what Someone Else probably means.
Cheers & hth.,
In the simplest of terms:
int a = 0; // initialization of a to 0
a = 1; // assignment of a to 1
For built in types its relatively straight forward. For user defined types it can get more complex. Have a look at this article.
For instance:
class A
{
public:
A() : val_(0) // initializer list, initializes val_
{}
A(const int v) : val_(v) // initializes val_
{}
A(const A& rhs) : val_(rhs.val_) // still initialization of val_
{}
private:
int val_;
};
// all initialization:
A a;
A a2(4);
A a3(a2);
a = a3; // assignment
Initialization is creating an instance(of type) with certain value.
int i = 0;
Assignment is to give value to an already created instance(of type).
int i;
i = 0
To Answer your edited Question:
What is the difference between Initializing And Assignment inside constructor? &
What is the advantage?
There is a difference between Initializing a member using initializer list and assigning it an value inside the constructor body.
When you initialize fields via initializer list the constructors will be called once.
If you use the assignment then the fields will be first initialized with default constructors and then reassigned (via assignment operator) with actual values.
As you see there is an additional overhead of creation & assignment in the latter, which might be considerable for user defined classes.
For an integer data type or POD class members there is no practical overhead.
An Code Example:
class Myclass
{
public:
Myclass (unsigned int param) : param_ (param)
{
}
unsigned int param () const
{
return param_;
}
private:
unsigned int param_;
};
In the above example:
Myclass (unsigned int param) : param_ (param)
This construct is called a Member Initializer List in C++.
It initializes a member param_ to a value param.
When do you HAVE TO use member Initializer list?
You will have(rather forced) to use a Member Initializer list if:
Your class has a reference member
Your class has a const member or
Your class doesn't have a default constructor
Initialisation: giving an object an initial value:
int a(0);
int b = 2;
int c = a;
int d(c);
std::vector<int> e;
Assignment: assigning a new value to an object:
a = b;
b = 5;
c = a;
d = 2;
In C the general syntax for initialization is with {}:
struct toto { unsigned a; double c[2] };
struct toto T = { 3, { 4.5, 3.1 } };
struct toto S = { .c = { [1] = 7.0 }, .a = 32 };
The one for S is called "designated initializers" and is only available from C99 onward.
Fields that are omitted are automatically initialized with the
correct 0 for the corresponding type.
this syntax applies even to basic data types like double r = { 1.0
};
There is a catchall initializer that sets all fields to 0, namely { 0 }.
if the variable is of static linkage all expressions of the
initializer must be constant expressions
This {} syntax can not be used directly for assignment, but in C99 you can use compound literals instead like
S = (struct toto){ .c = { [1] = 5.0 } };
So by first creating a temporary object on the RHS and assigning this to your object.
One thing that nobody has yet mentioned is the difference between initialisation and assignment of class fields in the constructor.
Let us consider the class:
class Thing
{
int num;
char c;
public:
Thing();
};
Thing::Thing()
: num(5)
{
c = 'a';
}
What we have here is a constructor that initialises Thing::num to the value of 5, and assigns 'a' to Thing::c. In this case the difference is minor, but as was said before if you were to substitute int and char in this example for some arbitrary classes, we would be talking about the difference between calling a parameterised constructor versus a default constructor followed by operator= function.

newbie: C++ question about initialization lists

Let's say I have an array of objects declared in my header. The size of the array could be very large. In my source file, I create the constructor for my class and I'd like to initialize all the objects in my array. If these objects are not being constructed with a zero-parameter constructor, I am told these need to be put in my initialization list.
My question is if I want to use a loop to initialize this possibly large array of objects, that wouldn't go in the initialization list, would it? I wouldn't want to put in my initialization list: str1("1"), str2("2"), ... , strn("n"). Could a loop to initialize all these objects go in the header or possibly in the body of the constructor?
Please let me know. I have not seen an example of this.
Thanks,
jbu
You are not able to loop in an initializer list, however there is no issue with looping in the constructor body, so long as the object type has a valid assignment operator. The objects in the array will be first initialized using their zero-parameter constructor, before the constructor body. Then in the body you will re-assign them to whatever they need to be.
Also note that if each object in the array is to be initialized using the same NON-zero parameter constructor, you can use an std::vector type, and in the initializer list, specify the default non-zero constructor to be used when allocating the internal array, ie:
// in .h
class MyClass
{
...
MyClass();
private:
vector<SomeObject> objects;
};
// in .cpp
MyClass::MyClass()
: objects(100,SomeObject(10, "somestring"))
{
}
you'll have to wait for C++0x to initialize an array in the initializer list.
struct S {
int a[3];
S(int x, int y, int z) :a{x,y,z} { /*…*/ }; // solution to old problem
};
It is possible to do like this using boost assign to declare a const vector of elements :
#include<vector>
#include<iostream>
#include<boost/foreach.hpp>
#include<boost/assign.hpp>
#include<boost/assign/list_of.hpp>
#include<boost/assign/std/vector.hpp>
using namespace std;
using namespace boost;
using namespace boost::assign;
typedef vector<int> int_vector;
const int_vector my_const_vector = list_of
(1)(2)(3)(5)(8)(13)(21)(34)(55)(89);
class myClass
{
public :
// initialization list used in the constructor
myClass(const int_vector & vec)
: m_member_vector(int_vector(vec.begin(), vec.end()))
{}
void print() const
{
BOOST_FOREACH(int i, m_member_vector)
{ cout << i << endl; }
}
private :
int_vector m_member_vector;
};
void main()
{
myClass m(my_const_vector);
m.print();
}
You can get boost from here . I realize this isn't arrays but this does solve your problem - in a way
You cannot initialize arrays in an initialization list. You have to do it in the body of the constructor.
If the thing you want to have an array of is not default-constructable, the simplest solution is to use a std::vector instead of a raw array. That way you can construct the elements as you add them within the constructor body.
But if you insist on having as a class member a raw array of objects whose type does not have a default constructor, then your only real option is to make it an array of pointers-to-Foo rather than an array of Foo.
Not a "newbie" answer, nor one I would use, but you can have a look at the boost preprocessor library, which allows you to create loops with the preprocessor.
From your question it looks like you'd like to initialize each element of the array with a different parameter (as implied by the list str1("1"), str2("2"), strn("n")). This is not possible with the current C++; And as TimW noted C++0X will allow support for this type of initialization via sequence constructors.
Having said that, it seems what you want to do is run-time initialization of these values ("1"), ("2")...("n") (Do you know these values at compile time?). If that's the case, I don't think you can use an initialization list even in C++0X. If that's not the case(compile time parameter passing for this very large array), then the preprocessor magic is the way to go.