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.
Related
I find plenty of articles and SO questions about zero- and default-initialization of POD types, but I've not found any that discuss initialization of POD types as class members in class constructor initialization lists. I'm sure there's probably a SO question or article about it but I've not found any.
So if I have a class...
class MyClass
{
public:
MyClass() : anArrayOfInt() {}
private:
int anArrayOfInt[10];
}
...what can I know about the state of anInt after construction of a MyClass object? I've noted by empirical testing that with the above code on GCC 6.4.0, anArrayOfInt is all-zeros after a stack-allocated instance of MyClass is created, but if I change the code to this:
class MyClass
{
public:
MyClass() {}
private:
int anArrayOfInt[10];
}
...then stack-allocated instances no longer have all-zeros in anArrayOfInt. In my real case (the case that prompted me to write this question), this is causing test failures. I noted that if I change the code as follows:
class MyClass
{
public:
MyClass() { memset(anArrayOfInt, 0, sizeof(anArrayOfInt)); }
private:
int anArrayOfInt[10];
}
...then my tests again pass, even without listing anArrayOfInt() in the constructor initialization list. So it seems I need anArrayOfInt() in the initialization list, but before I revert back from the memset() version to the initialization list version, I need to know for certain that the initialization list entry "anArrayOfInt()" is guaranteed to zero the bytes of anArrayOfInt, or if that's just GCC's behavior and I can't count on it on other compilers.
If it matters, GCC 6.4.0 is where we run unit tests, but our target is the IAR embedded compiler for RX MCUs, which is still in C++03-land.
So if I have a class...
MyClass() : anArrayOfInt() {}
...what can I know about the state of anInt after construction of a MyClass object?
You've value initialised the member, so we know that it contains zeroes.
I need to know for certain that the initialization list entry "anArrayOfInt()" is guaranteed to zero the bytes of anArrayOfInt, or if that's just GCC's behavior and I can't count on it on other compilers.
Yes, value initialisation guarantees that integers are initialised to zero.
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.
Can someone please quote an example code when we should not use initialisation list in the constructor and how that can be overcome with assignment?
I am looking for an example for the below statement
This might happen when your class has two constructors that need to initialize the this object's data members in different orders. Or it might happen when two data members are self-referential. Or when a data-member needs a reference to the this object, and you want to avoid a compiler warning about using the this keyword prior to the { that begins the constructor's body (when your particular compiler happens to issue that particular warning). Or when you need to do an if/throw test on a variable (parameter, global, etc.) prior to using that variable to initialize one of your this members.
I believe the main concept that the author of your statement was referring to is the fact that calls made to variables in the initialisation list occur not in the order you see them in the initialisation list, but in the order the variables are listed in the class definition.
That means
if you have two different constructors which use initialisation lists, they must initialise them in the same sequence
your control over sequencing (which may be important if you have mutually-dependent members) is limited
I'd recommend taking a look at Scott Meyer's Effective C++ which covers this (amongst many, many other useful and informative topics).
Here are some examples:
This might happen when your class has two constructors that need to
initialize the this object's data members in different orders.
class Example1 {
public:
Example1(std::string decoded, std::string encoded)
: decoded_(decoded),
encoded_(encoded) {}
explicit Example1(std::string encoded)
: decoded_(), // Can't use "decoded_(Decode())" since "encoded_" isn't initialised
encoded_(encoded) {
decoded_ = Decode(); // Assign here instead of initialising
}
private:
std::string Decode(); // decodes class member "encoded_"
std::string decoded_, encoded_;
};
In this example, decoded_ will always be initialised before encoded_ since that's the order in which they are declared in the class, even if we swap their order in the initialisation list.
Or when a data-member needs a reference to the this object, and you
want to avoid a compiler warning about using the this keyword prior to
the { that begins the constructor's body (when your particular
compiler happens to issue that particular warning).
class Example2 {
public:
Example2() : functor_() {
functor_ = std::bind(&Example2::Do, this);
}
private:
void Do();
std::function<void()> functor_;
};
Here, functor_ needs to use this when it is initialised/assigned. If we were to intialise functor_ in the initialisation list, the this pointer would be referring to an object which at that point wasn't fully initialised. That could be safe depending on the particular circumstances, but the foolproof option is to defer setting functor_ until inside the constructor body, by which point this does refer to a fully-initialised object.
Or when you need to do an if/throw test on a variable (parameter,
global, etc.) prior to using that variable to initialize one of your
this members.
class Example3 {
public:
Example3(int force, int acceleration)
: force_(force),
acceleration_(acceleration),
mass_(0) {
if (acceleration_ == 0)
throw std::exception("Can't divide by 0");
mass_ = force_ / acceleration_;
}
private:
int force_, acceleration_, mass_;
};
Hopefully this is self-explanatory.
I'm not sure what is meant by
when two data members are self-referential
so I can't give an example for that I'm afraid.
My gut feeling is it is not. I am in the following situation:
class PluginLoader
{
public:
Builder* const p_Builder;
Logger* const p_Logger;
//Others
};
PluginLoader::PluginLoader(Builder* const pBuilder)
:p_Builder(pBuilder), p_Logger(pBuilder->GetLogger())
{
//Stuff
}
Or should I change the constructor and pass a Logger* const from where PluginLoader is constructed?
That's perfectly fine and normal. p_Builder was initialized before it.
What you have is fine. However, I just want to warn you to be careful not to do this: (GMan alluded to this, I just wanted to make it perfectly clear)
class PluginLoader
{
public:
Logger* const p_Logger; // p_Logger is listed first before p_Builder
Builder* const p_Builder;
//Others
};
PluginLoader::PluginLoader(Builder* const pBuilder)
:p_Builder(pBuilder),
p_Logger(p_Builder->GetLogger()) // Though listed 2nd, it is called first.
// This wouldn't be a problem if pBuilder
// was used instead of p_Builder
{
//Stuff
}
Note that I made 2 changes to your code. First, in the class definition, I declared p_Logger before p_Builder. Second, I used the member p_Builder to initialize p_Logger, instead of the parameter.
Either one of these changes would be fine, but together they introduce a bug, because p_Logger is initialized first, and you use the uninitialized p_Builder to initialize it.
Just always remember that the members are initialized in the order they appear in the class definition. And the order you put them in your initialization list is irrelevant.
Perfectly good practice.
I would suggest this (but its on a purely personal level):
instead of having functions called in your constructor, to group them in a init function, only for flexibility purposes: if you later have to create other constructors.
This is a problem I come across often. The following examples illustrates it:
struct A {
int m_SomeNumber;
};
struct B {
B( A & RequiredObject );
private:
A & m_RequiredObject;
};
struct C {
C( );
private:
A m_ObjectA;
B m_ObjectB;
};
The implementation of the constructor of C looks something like this:
C::C( )
: B( m_ObjectA )
{ }
Since the order of initialization is not defined, m_ObjectA might be uninitialized when the constructor of m_ObjectB is called, resulting in undefined behavior. One way to force a certain order of initialization would be to make the members pointers and initialize them in the constructor body, thus forcing the correct order, but this is ugly for several reasons. Is there any way to force a certain initializtion order using the initialization-list of the constructor? If not, do you have any other suggestions how to handle this.
Since the order of initialization is not defined
On the contrary, it is well-defined. The order of initialization is equal to the order in which the member variables are declared in your class (and that’s regardless of the actual order of the initialization list! It’s therefore a good idea to let the initialization list order match the order of the declarations to avoid nasty surprises).