I know I can initialize int variables in a constructor with a member initialization list, but can I initialize an enum type in an member initialization list like in the example below?
enum number{zero, one, two, three};
class Example{
int test;
number number_enum;
public:
Example(int test_arg, number number_enum_arg): test(test_arg),
number_enum(number_enum_arg){
}
};
Also, I know it is better to initialize variables using an member initialization list, rather than using the assignment operator, but exactly is that?
The code in your example will work, you can initialize enums and virtually all types in an initializer list. Add a line to your constructor to print it out, you'll see.
Related
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.
I want to make a vector in private part of a class that hold only 10 integers
but I get " syntax error 'constant' " while making this vector in the private part of class.
I know that I can use a constant array instead of vector but why I can't use vector with constant capacity in a class?
also if I make this vector in main() function every thing is fine but in the class I get this error!
class A
{
public:
// constructor
private:
std::vector<int> tests(10); // here I get error
};
Default member initializer (since C++11) doesn't support parentheses initializer, but only brace or equals initializer.
Through a default member initializer, which is simply a brace or equals initializer included in the member declaration, which is used if the member is omitted in the member initializer list
Note that for std::vector, using brace initializer might lead to effect you don't want. (e.g. std::vector<int>{10} initializes a vector with 1 element with value 10.) You can use equals initializer like
std::vector<int> tests = std::vector<int>(10);
BTW: If the size is fixed, you can use std::array instead.
std::array<int, 10> tests;
The initialization of your member variable must be in the constructor list of your class.
class A
{
public:
A(); // contructor
private:
std::vector<int> tests;
};
A::A() :
tests(10)
{
// constructor logic
}
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.
I'd like to understand what's the differences of using one form rather than the other (if any).
Code 1 (init directly on variables):
#include <iostream>
using namespace std;
class Test
{
public:
Test() {
cout<< count;
}
~Test();
private:
int count=10;
};
int main()
{
Test* test = new Test();
}
Code 2 (init with initialization list on constructor):
#include <iostream>
using namespace std;
class Test
{
public:
Test() : count(10) {
cout<< count;
}
~Test();
private:
int count;
};
int main()
{
Test* test = new Test();
}
Is there any difference in the semantics, or it is just syntactic?
Member initialization
In both cases we are talking about member initialization.
Keep in mind that the members are initialized in the sequence in which they are declared in the class.
Code 2: Member initializer list
In the second version:
Test() : count(10) {
: count(10) is a constructor initializer (ctor-initializer) and count(10) is a member initializer as part of the member initializer list. I like to think of this as the 'real' or primary way that the initialization happens, but it does not determine the sequence of initialization.
Code 1: Default member initializer
In the first version:
private:
int count=10;
count has a default member intitializer. It is the fallback option. It will be used as a member initializer if none is present in the constructor, but in the class the sequence of members for initialization is determined.
From section 12.6.2 Initializing bases and members, item 10 of the standard:
If a given non-static data member has both a
brace-or-equal-initializer and a mem-initializer, the initialization
specified by the mem-initializer is performed, and the non-static data
member’s brace-or-equal-initializer is ignored. [ Example: Given
struct A {
int i = / some integer expression with side effects / ;
A(int arg) : i(arg) { }
// ...
};
the A(int) constructor will simply initialize i to the value of arg,
and the side effects in i’s brace-or-equalinitializer will not take
place. —end example ]
Something else to keep in mind would be that if you introduce a non-static data member initializer then a struct will no longer be considered an aggregate in C++11, but this has been updated for C++14.
Differences
what's the differences of using one form rather than the other (if
any).
The difference is the priority given to the two options. A constructor initializer, directly specified, has precedence. In both cases we end up with a member initializer via different paths.
It is best to use the default member initializer because
then the compiler can use that information to generate the constructor's initializer list for you and it might be able to optimize.
You can see all the defaults in one place and in sequence.
It reduces duplication. You could then only put the exceptions in the manually specified member initializer list.
In the C++ Core Guidelines (see note 1 below), Guideline C.48 recommends the first approach (in-class initializers.) The reasoning provided is:
Makes it explicit that the same value is expected to be used in all constructors. Avoids repetition. Avoids maintenance problems. It leads to the shortest and most efficient code.
In fact if your constructor does nothing but initialize member variables, as in your question, then Guideline C.45 is firmer still, saying to use in-class initializers for sure. It explains that
Using in-class member initializers lets the compiler generate the function for you. The compiler-generated function can be more efficient.
I am not going to argue with Stroustrup, Sutter, and several hundred of their friends and colleagues even if I haven't written a compiler so I can't prove it's more efficient. Use in-class initializers wherever you can.
If you're not familiar with the guidelines do follow the links to see sample code and more explanations.
The difference I can think of is that member initializer list is prior to default member initializer.
Through a default member initializer, which is simply a brace or
equals initializer included in the member declaration, which is used
if the member is omitted in the member initializer list.
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 example:
class Test
{
public:
Test() {} // count will be 10 since it's omitted in the member initializer list
Test(int c) : count(c) {} // count's value will be c, the default member initializer is ignored.
private:
int count = 10;
};
There is no difference in the code. The difference would come if you would be would have more than one constructor overload and in more than one count would be 10. With the first version you would have less writing to do.
class Test
{
public:
Test() = default;
Test(int b) : b(b) {} // a = 1, c = 3
~Test();
private:
int a = 1;
int b = 2;
int c = 3;
};
As opposed to the second version where the above code would look like this:
class Test
{
public:
Test() : a(1), b(2), c(3) {}
Test(int b) : a(1), b(b), c(3) {}
~Test();
private:
int a;
int b;
int c;
};
The difference gets bigger with more member variables.
When you initialise next to the declaration of the member, this is valid only in C++11 onwards, so if you're in C++98/03 you outright cannot do this.
If the value never changes, you could choose to make this a constexpr static instead and the compiler would then be required to not use any extra storage for the value (so long as you don't define it) and instant use constant propagation wherever the value is used instead.
One disadvantage of using the by-declaration syntax is that it must be in the header, which will result in a recompile of all translation units that include the header every time you want to change its value. If this takes a long time, that might be unacceptable.
Another difference is that using the member initialisation list lets you change the value for each constructor, whilst using the by-declaration version only allows you to specify one value for all constructors (although you could overwrite this value ... but I'd personally avoid this as it could get quite confusing!).
As an aside, there's no need to use new here to create an instance of Test. This is a common mistake when people come to the language from other languages and I wanted to make you aware. There are of course many uses for doing this outside of your example.
By instantiating an object in C++ with the following class I get a segmentation fault or aborts, depending on the order declaring member variables. E. g. putting mMemberVar and mAnotherMemberVar after mAnotherCountVar results in a segfault. From this listing I removed a std::ofstream from the member variables, which caused the segmentation fault independent of its position.
I think the order is not directly the problem, but what do you think could the reason be? This class is part of a huge project, but this in this class is the place, where the error appeared the first time.
class COneClass : public IInterface
{
public:
COneClass();
virtual ~COneClass();
static const unsigned int sStaticVar;
static const unsigned int sAnotherStaticVar;
private:
COneClass();
COneClass(const COneClass& );
COneClass& operator=(const COneClass& );
int mMemberVar;
int mAnotherMemberVar;
bool mIsActive;
bool mBoolMemberVar;
bool mAnotherBoolMemberVar;
unsigned int mCountVar;
unsigned int mAnotherCountVar;
};
COneClass::COneClass() :
mMemberVar(0),
mAnotherMemberVar(0),
mIsActive(false),
mBoolMemberVar(false),
mAnotherBoolMemberVar(false),
mCountVar(sStaticVar),
mAnotherCountVar(sAnotherStaticVar)
{
}
the class members are initinised by the order they are declared. the order in the init list does not matter. In your case it's this order:
mMemberVar -> mAnotherMemberVar -> mIsActive -> mBoolMemberVar -> mAnotherBoolMemberVar -> mCountVar -> mAnotherCountVar;
Perhaps it is a case of the "static initialization order fiasco", http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.16, as a result of initializing mCountVar and mAnotherCountVar with static members?
You could init to zero in the list and then assign in the body of the constructor.
Could be "static initialization order fiasco" judging by the fact that you have public static variables and a private constructor (speaking of which how can you have a public and private definition of the constructor???). These signs indicate the possibility that there is a dependency with other classes here.
The members’ constructors are called before the body of the containing class’ own constructor
is executed. The constructors are called in the order in which they are declared in the class rather
than the order in which they appear in the initializer list.
To avoid confusion, it is best to specify the initializers in declaration order.
The member destructors are called in the reverse order of construction every thing work properly
class MyClass//**1: mem-init**
{
private:
long number;
bool on;
public:
MyClass(long n, bool ison) : number(n), on(ison) {}
};
MyClass(long n, bool ison) //2 initialization within constructor's body
{
number = n;
on = ison;
}
There is no substantial difference between the two forms in the case of MyClass's constructor. This is due to the way mem-initialization lists are processed by the compiler. The compiler scans the mem-initialization list and inserts the initialization code into the constructor's body before any user-written code. Thus, the constructor in the first example is expanded by the compiler into the constructor in the second example. Nonetheless, the choice between using a mem-initialization list and initialization inside the constructor's body is significant in the following four cases:
Initialization of const members
Initialization of reference members
Passing arguments to a constructor of a base class or an embedded object
Initialization of member objects
I think the whole class is not directly the problem. Can you produce a minimal code that crashes just by using this class? It seems to me that the problem is somewhere else in your code base.
However, you may add a bool Invariant() const; function to that class and call it (only in debug builds) with assert(Invariant()); at the end of your constructor and on entering and exiting all your public functions. This might help you to "crash early, crash often" and hence point you to some of the problematic code.
This doesn't look like your real code. But be aware in your real code, that class members are constructed in the order they are defined in the class, REGARDLESS of the order of the initializer list in the constructor. Given that you mention changing the order of the members in the class affects the problem, this might be what's wrong. For example, your code might do something like this:
class MyClass {
public:
const int member1;
const int member2;
MyClass() {
: member2(0),
: member1(member2) // ERROR: this runs first because member1 is defined first
// member2 not yet constructed; assigns undefined value to member1
{}
};
There's nothing in the code you've posted which is in any way abnormal. Either something in the IInterface constructor is failing, or something else entirely is going wrong. Perhaps you've a buffer overflow somewhere which is reading the data you've changing the structural order of.