Sorry if title is confusing, I couldn't find an easy way to write it in a simple sentence. Anyways, the issue I'm facing:
// header:
class SomeThing
{
private:
SomeThing() {} // <- so users of this class can't come up
// with non-initialized instances, but
// but the implementation can.
int some_data; // <- a few bytes of memory, the default
// constructor SomeThing() doesn't initialize it
public:
SomeThing(blablabla ctor arguments);
static SomeThing getThatThing(blablabla arguments);
static void generateLookupTables();
private:
// declarations of lookup tables
static std::array<SomeThing, 64> lookup_table_0;
static SomeThing lookup_table_1[64];
};
The getThatThing function is meant to return an instance from a lookup table.
// in the implementation file - definitions of lookup tables
std::array<SomeThing, 64> SomeThing::lookup_table_0; // error
SomeThing Something::lookup_table_1[64]; // <- works fine
I just can't use a std::array of Something, unless I add a public ctor SomeThing() in the class. It works fine with old-style arrays, I can define the array, and fill it up in the SomeThing::generateLookupTables() function. Apparently the type std::array<SomeThing, 64> does not have a constructor. Any ideas on how to make it work, or maybe a better structure for this concept?
============= EDIT =======
The friend std::array<SomeThing, 64> approach seems like a nice idea, but:
It is going to be used in arrays in other places as well. I would like to guarantee this class to always keep certain invariants towards to external users. With this friendly array, a user can accidentally create an uninitialised array of SomeThing.
Also, the lookup tables are generated using a rather complicated process, can't be done per inline, as in std::array<SomeThing, 64> SomeThing::lookup_table_0(some value)
The std::array<SomeThing, 64> class clearly doesn't have access to the private default constructor when it tries to define the instance. You can give it the necessary access by adding
friend class std::array<SomeThing, 64>;
to the definition of SomeThing.
The solution:
std::array<SomeThing, 64> SomeThing::lookup_table_0 {{ }};
Note: as explained here, {{}} is required to value-initialize the std::array without warnings in gcc. = {} and {} are correct but gcc warns anyway.
The key to the solution is that some form of initializer must be present.
A terminology check first: all objects are initialized in C++. There are three forms of this, default, value and zero. There are no "non-initialized" objects ; objects with no explicit initializer are called default-initialized. In some circumstances this means the member variables of the object may be indeterminate ("garbage").
What is the problem with the no-initializer version? Firstly, the constructor for std::array<SomeThing, 64> is defined as deleted because the declaration std::array<SomeThing, 64> x; would be ill-formed (due to lack of an accessible default constructor for SomeThing, of course).
That means that any code which attempts to use the default constructor for std::array<SomeThing, 64> is in turn ill-formed. The definition:
std::array<SomeThing, 64> SomeThing::lookup_table_0;
does attempt to use the default constructor, so it is ill-formed. However once you start introducing initializers, then the default constructor for std::array is no longer in play; since std::array is an aggregate then aggregate initialization occurs which bypasses the implicitly-generated constructor(s). (If there were any user-declared constructors then it would no longer be an aggregate).
The version with initializers works because of [dcl.init]/13 (n3936):
An initializer for a static member is in the scope of the member’s class
The definition of list-initialization transforms { } to { SomeThing() } here.
As your constructor is private, std::array can't use it.
You may add friend class std::array<SomeThing, 64>; in SomeThing to give access to the constructor.
An alternative is to use the available public constructor to initialize the element of array:
std::array<SomeThing, 64> SomeThing::lookup_table_0{
SomeThing(blablabla_ctor_arguments), ..
};
EDIT:
You can even do, if you have your move or copy constructor available:
std::array<SomeThing, 64> SomeThing::lookup_table_0{ SomeThing() };
to have your whole array default initialized.
Related
I looked at a piece of code and I am trying to understand how it works and so here is a minimal working example
template <typename T>
class A
{
public:
A() : _mem(T()) {};
private:
T _mem;
};
The first thing I was not exactly clear about is the initialisation of _mem in the initialiser list. What is this technique(?) called? If I look in the debugger _mem is set to 0. If there is a c++11 way to do the same thing could I receive some comments on that?
This is just to safeguard against an uninitialized A::_mem when T is a POD type or a built-in type (like an int). Using a constructor initializer list of : _mem(T()) will default construct a T and initialize _mem with it. For example:
struct POD {
int num;
};
// ...
A<POD> a;
Here, a._mem would be unitialized (in this case, this means a._mem.num is unitialized.) The : _mem(T()) prevents that from happening and will initialize a._mem.num to 0.
However, since C++11 you can just use inline initialization instead:
template <typename T>
class A {
public:
A() {};
private:
T _mem{};
};
T _mem{}; will default-construct _mem, which in turn means POD::num will be default-constructed, which for an int means it will be zero-initialized.
If this has a name, I don't know it.
What's happening:
T() constructs a temporary T and Zero Initializes it.
_mem(T()) makes _mem a copy of the temporary T. Note: A modern compiler will almost certainly elide the copy and simply zero initialize _mem. This still requires that T be copy-or-moveable, so _mem(T()) and _mem() are not exactly the same.
The only relevant C++ 11 difference I can think of is you can use curly braces, _mem{T{}}, for List Initialization. Not useful here, but very useful in other circumstances.
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.
Rather surprised to find this question not asked before. Actually, it has been asked before but the questions are VERY DIFFERENT to mine. They are too complicated and absurd while I'll keep it simple and to the point. That is why this question warrants to be posted.
Now, when I do this,
struct A {
int a = -1;
};
I get the following error:
ANSI C++ forbids in-class initialization of non-const static member a
Now, along with the workaround can someone please tell me THE BEST way of initializing a struct member variable with a default value?
First, let's look at the error:
ANSI C++ forbids in-class initialization of non-const static member a
Initialization of a true instance member, which resides within the memory of an instance of your struct is the responsibility of this struct's constructor.
A static member, though defined inside the definition of a particular class/struct type, does not actually reside as a member of any instances of this particular type. Hence, it's not subject to explaining which value to assign it in a constructor body. It makes sense, we don't need any instances of this type for the static member to be well-initialized.
Normally, people write member initialization in the constructor like this:
struct SomeType
{
int i;
SomeType()
{
i = 1;
}
}
But this is actually not initialization, but assignment. By the time you enter the body of the constructor, what you've done is default-initialize members. In the case of a fundamental type like an int, "default-initialization" basically boils down to "eh, just use whatever value was in those bytes I gave you."
What happens next is that you ask i to now adopt the value 1 via the assignment operator. For a trivial class like this, the difference is imperceptible. But when you have const members (which obviously cannot be tramped over with a new value by the time they are built), and more complex members which cannot be default-initialized (because they don't make available a visible constructor with zero parameters), you'll soon discover you cannot get the code to compile.
The correct way is:
struct SomeType
{
int i;
SomeType() : i(1)
{
}
}
This way you get members to be initialized rather than assigned to. You can initialize more than one by comma-separating them. One word of caution, they're initialized in the order of declaration inside your struct, not how you order them in this expression.
Sometimes you may see members initialized with braces (something like i{1} rather i(c)). The differences can be subtle, most of the time it's the same, and current revisions of the Standard are trying to smooth out some wrinkles. But that is all outside the scope of this question.
Update:
Bear in mind that what you're attempting to write is now valid C++ code, and has been since ratification of C++11. The feature is called "Non-static data member initializers", and I suspect you're using some version of Visual Studio, which still lists support as "Partial" for this particular feature. Think of it as a short-hand form of the member initialization syntax I described before, automatically inserted in any constructor you declare for this particular type.
You could make a default constructor
struct A {
A() : a{-1} {}
int a;
};
C++11 introduced this:
struct MyClass {
int foo = 0; //*
};
Until now I've been using this without thinking about it, but now I'm wondering:
Is this initialization doing/executing any actual initialization at this particular line (//* in the code), or is this a mere convenience notation that only does/executes something later, when the object is actually constructed?
Not sure what you mean by "later" and "at this particular line", but the above is equivalent to the following:
struct MyClass {
MyClass() : foo(0) { }
};
So if I understand your question correctly, then the answer is: "Yes, only when the object is actually constructed".
Declarations are not executable code, they do not execute anything. This is merely a convenient notation for inserting initialization of foo to zero into every constructor that you define (or into an implicitly defined default constructor, if you do not define any constructors yourself).
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.