C++ constructor syntax and zero-initialization - c++

This is a short question about syntax in c++:
class arrayInit {
public:
bool vars[2];
arrayInit() : vars() {} //1
};
class array {
public:
bool vars[2];
array() {} //2
};
What does 1 and 2 do?
Why they don't zero initialize like this: bool vars[2]={};?
What is the purpose of arrayInit() : and array()? and what is it called so I could search for it?
It's from: https://msujaws.wordpress.com/2010/06/16/initializing-an-array-in-c/

What does 1 and 2 do?
Both 1 and 2 define the default constructor for the respective type
Why they don't zero initialize like this: bool vars[2]={};?
They could if they were using a compiler with c++11 support. Also var() will value initialize the array which is same as vars[2] = {} will explicitly initialize all elements to false
What is the purpose of arrayInit() : and array()? and what is it
called so I could search for it?
They are called the default constructors. C++ compiler will create them for you unless you want to do something special in them. If you were mentioning about what is written beyond the : (colon), that expression is called the initializer list
Read more here

What does 1 and 2 do?
Both allow you to override the default initialization for an array.
InitArray is specifically initializing the vars array with no parameters, I believe it will assume 0 as the default parameter.
Array is not specifically initializing the array, so it is falling back to a default initialization case.
Why they don't zero initialize like this: bool vars[2]={};?
You could do this, this is just another option which encapsulates the bool array in a class to allow you to provide other functionality if you wish.
What is the purpose of arrayInit() : and array()?
If you want default functionality, there is no need to encapsulate the array in its own class. Encapsulation allows you to encapsulate a type to provide different functionality from the default, you could go on to add methods for addition, subtraction, or anything you can think up and have it perform the methods in the way that you specify.
and what is it called so I could search for it?
Good question; Encapsulation, class initialization, array initialization.
http://www.cplusplus.com/doc/tutorial/classes/

Both arrayInit() and array() are default constructors. If the default constructor is missing and other constructors are available, you cannot declare an object from that class type without calling the other constructors e.g. you cannot do this arrayInit arr; without the default constructor.
The part : vars() is called the initialization list. You can read more about them in this link: http://en.cppreference.com/w/cpp/language/initializer_list

Related

Pass function parameter directly to class variable

I have a class lazy_segment_tree. This is the current constructor
template<typename T>
struct lazy_segment_tree{
int n;
int H;
T base;
vector<T> segtree;
vector<T> lazytree;
T (*join)(T,T);
T (*assign)(int,T,T);
lazy_segment_tree(vector<T> &seq, T (*merge)(T,T), T (*create)(int, T,T), T defvalue){
join=merge;
assign=create;
base=defvalue;
n=seq.size();
}
};
Can't I directly make the construction parameters go to the values in the class variable?
I am not 100% sure what do you mean by 'directly'.
But in this case you should use initializer list to initialize the member variables. More on initializer lists here.
Applied to your code, the constructor would now look like this:
lazy_segment_tree(vector<T> &seq, T (*merge)(T,T), T (*create)(int, T,T), T defvalue)
: join(merge)
, assign(create)
, base(defvalue)
, n(seq.size())
{}
In your original code, all the members are first default-constructed during initialization of the class. Then, the body of the constructor is called where you use '=' to copy assign the constructor parameters.
When initializer list is used, the members are directly constructed with specified parameters.
Depending on what T might be, it may or may not make real difference. Nevertheless, initializer lists are the standard way to initialize class members and you should use it if possible.

Can't initialize field outside initializer list

I'm having trouble with something that seems very easy, so I must be overlooking something.
I need to construct a class that has a field that is also a class (non-POD). The class of the field has a default constructor and a "real" constructor. The thing is that I really can't construct the field in the initializer list, because in reality the constructor has a parameter that is a vector which needs a somewhat complex for loop to fill.
Here is a minimal example that reproduces the problem.
ConstructorsTest.h:
class SomeProperty {
public:
SomeProperty(int param1); //Ordinary constructor.
SomeProperty(); //Default constructor.
int param1;
};
class ConstructorsTest {
ConstructorsTest();
SomeProperty the_property;
};
ConstructorsTest.cpp:
#include "ConstructorsTest.h"
ConstructorsTest::ConstructorsTest() {
the_property(4);
}
SomeProperty::SomeProperty(int param1) : param1(param1) {}
SomeProperty::SomeProperty() : param1(0) {} //Default constructor, doesn't matter.
But this gives a compile error:
ConstructorsTest.cpp: In constructor 'ConstructorsTest::ConstructorsTest()':
ConstructorsTest.cpp:4:19: error: no match for call to '(SomeProperty) (int)'
the_property(4);
^
It gives no suggestions like it usually would of what functions could have been intended instead.
In the above example I would just initialize the_property in the initializer list, but in reality the 4 is actually a complex vector that needs to be generated first, so I really can't. Moving the_property(4) to the initializer list causes the compilation to succeed.
Other similar threads mention that the object must have a default constructor, or that it can't be const. Both requirements seem to have been met, here.
You can't initialize data member inside the constructor's body. (the_property(4); is just trying to invoke the_property as a functor.) You can only assign them like:
ConstructorsTest::ConstructorsTest() {
the_property = ...;
}
but in reality the 4 is actually a complex vector that needs to be generated first
You can add a member function which generate the necessary data, and use it to initialize the data member in member initializer list. e.g.
class ConstructorsTest {
...
static int generateData();
};
int ConstructorsTest::generateData() {
return ...;
}
ConstructorsTest::ConstructorsTest() : the_property(generateData()) {
}
You cannot initialize a variable twice.1 When your constructor has started, all member subobjects will have been constructed. If you do not provide a member initializer in the constructor, or a default member initializer in the class definition, then it will perform default initialization. Regardless of what form it takes, you can't construct it again.
Complex multi-statement initialization is best done via a lambda function:
ConstructorsTest::ConstructorsTest()
: the_property( []{ /* Do Complex Initialization */}() )
{
}
1: Well... you can, but not like that. And you really shouldn't for cases as simple as this.

Default constructor for struct with Long and pointer

I am in the process of learning c++.
I have a struct like this:
struct Info {
const Long rate;
A* ptr;
}
I have a constructor which takes all the arguments as its parameters to initialize the struct. However, this struct is part of another class which will be serialized using boost serialization. In order to serialize that class I would need a default constructor for this struct. However, when I try to write a default constructor such as
Info () {
}
I get an error C2758 that the member rate should be initialized in the constructor.
How to get a default constructor for such a struct which I can use to serialize my class.
You need to initialize the constant value, so:
Info () : rate(0) {
}
The error is probably due to the fact that your Long class does not have a default constructor either.
There are two ways of fixing this:
Add a default constructor to Long, or
Add rate to the initialization list of Info's constructor.
You can see the msdn documentation for C2758 for a description of the error.
In basic term's, a const variable must be initialised in all constructors. The compiler enforces that any built in type or pointer member that is const must be initialised when the object is constructed, as you won't get a chance to give it a meaningful value after construction ( if you could change it after it was created, how is it const ? ).
Also, as a general rule of thumb, it is always a good idea to initialise members that don't have a default constructor ( built in types, pointers, and objects without default constructors ) to something, in all your class constructors. Otherwise they will either be initialised to some random value ( primitives or pointers ), or you will get a compile error ( objects without default constructors ).
Info()
: rate(0)
, ptr(nullptr)
{
}
If you are assigning values to some of your parameters from constructor arguments, don't forget to assign a value to the other members as well.
Info( Long rate)
: rate( rate )
, ptr(nullptr)
{
}
try this :
struct Info {
const Long rate;
A* ptr;
Info():rate(0){} // as Matthew guessed, call the correct Long constructor
// or define a default constructor for Long
};

C++: Where to initialize variables in constructor [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
C++ initialization lists
What are the pros/cons of initializing variables at option 1 vs option 2?
class MyClass
{
public:
MyClass( float f, char a );
private:
float mFloat;
char mCharacter;
bool mBoolean;
int mInteger;
};
MyClass::MyClass( float f, char a ) : mFloat( f ), mBoolean( true ) // option 1.
{
// option 2
mCharacter = a;
mInteger = 0;
}
Edit:
Why is option 2 so common?
In short, always prefer initialization lists when possible. 2 reasons:
If you do not mention a variable in a class's initialization list, the constructor will default initialize it before entering the body of the constructor you've written. This means that option 2 will lead to each variable being written to twice, once for the default initialization and once for the assignment in the constructor body.
Also, as mentioned by mwigdahl and avada in other answers, const members and reference members can only be initialized in an initialization list.
Also note that variables are always initialized on the order they are declared in the class declaration, not in the order they are listed in an initialization list (with proper warnings enabled a compiler will warn you if a list is written out of order). Similarly, destructors will call member destructors in the opposite order, last to first in the class declaration, after the code in your class's destructor has executed.
Although it doesn't apply to this specific example, Option 1 allows you to initialize member variables of reference type (or const type, as pointed out below). Option 2 doesn't. In general, Option 1 is the more powerful approach.
See Should my constructors use "initialization lists" or "assignment"?
Briefly: in your specific case, it does not change anything. But:
for class/struct members with constructors, it may be more efficient to use option 1.
only option 1 allows you to initialize reference members.
only option 1 allows you to initialize const members
only option 1 allows you to initialize base classes using their constructor
only option 2 allows you to initialize array or structs that do not have a constructor.
My guess for why option 2 is more common is that option 1 is not well-known, neither are its advantages. Option 2's syntax feels more natural to the new C++ programmer.
Option 1 allows you to use a place specified exactly for explicitly initializing member variables.
Option 1 allows you to initialize const members. This cannot be done with option 2 (as they are assigned to, not initialized).
Why must const members be intialized in the constructor initializer rather than in its body?
There are many other reasons. You should always initialize all member variables in the initialization list if possible.
http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.6

How to refrain from CS2512 correctly

Please help me with the following problem:
I have the following classes:
class ChemicalElement
{
private:
std::string _name;
void Init(const std::string& name);
public:
ChemicalElement(const std::string& name);
ChemicalElement(const ChemicalElement& ce);
};
class CombinationRule
{
private:
ChemicalElement _ce1;
ChemicalElement _ce2;
void Init(const ChemicalElement& ce1, const ChemicalElement& ce2);
public:
CombinationRule(const ChemicalElement& ce1, const ChemicalElement& ce2);
CombinationRule(const CombinationRule& rule);
};
The implementation is obvious. I intended to initialize the CombinationRule using the Init method to minimize code duplication. Alas, if I do not use "member initialization list" in each constructor the compiler complains with "error C2512: 'ChemicalElement' : no appropriate default constructor available". Is there an elegant way to solve this error instead of using a default constructor or member initialization list?
BTW: if there are any other problems in the classes definition please add it too. Since I'm revisiting C++ I want to be aware of them.
You should implement constructors of CombinationRule as follows so they will use appropriate constructors of ChemicalElement:
CombinationRule::CombinationRule(const ChemicalElement& ce1,
const ChemicalElement& ce2) : _ce1(ce1), _ce2(ce2)
{
...
}
CombinationRule::CombinationRule(const CombinationRule& rule) :
_ce1( rule._ce1 ), _ce2( rule._ce2 )
{
...
}
I think you are required to put a default constructor in any class where you define any other constructors, if you want to use objects of that class in any kind of array or container. The default constructor's implementation can just be an empty/no-op method though.
You shouldn't need to put in a member initialization list (although using a member initialization list can be more efficient in some cases, since that way your member variables are only initialized once, instead of being initialized once via their default constructor, and then written to a second time by your Init() method)
I think you want this
ChemicalElement * ce1;
I say this because I think its trying to run the default constructor on your CombinationRule and in turn needs to get a ChemicalElement for ce1 and ce2 ... but I could be wrong.
Pretty sure Krill's way is the way to specify the constructor of a variable for a specific constructor BUT i said f that and just made it so ce1 doesn't need to be constructed by the compiler :)
In this particular example I would go on with duplication (it's just writing two initializers, nothing to get obsessive about).
But assuming the real story is more complex: use OO facilities to avoid code duplication.
class CombinationRule : public ElementPair ...
or
class Combination { ElementPair twoElements; ...}
Where ElementPair contains two ChemicalElements and a single constructor (with common code), and Combination rule constructors initialize using constructor of ElementPair.
There are other approaches: initializing members with some InvalidChemicalElement instance or using pointers (auto_ptr) with NULL for InvalidChemicalElement.