I realized that in C++ you can initialize any structure with default values. I don't think that was possible under C. Is that correct?
Are there situations in which it still makes sense not to use such a default initialization? Or is it better in any case since it is safer?
I also saw that there are different ways to do this.
Is One Method Better Than Another? Or is it just a matter of taste?
struct STR_Foo {
int value{ 0 };
};
struct STR_Foo {
int value = 0;
};
struct STR_Foo {
int value = { 0 };
};
I realized that in C++ you can initialize any structure with default values. I don't think that was possible under C. Is that correct?
Yes.
Are there situations in which it still makes sense not to use such a default initialization?
If you target Older standard than C++11 - or cross-compatibility with C. Default member initialisers weren't in the language before that - and aren't in C.
If you target C++11 standard and you want the class to be an aggregate. Since C++14 default member initialisers don't disqualify a class from being an aggregate.
If you need an instance of the class to be initialised later and have measured that you cannot afford the very low overhead of redundant initialisation.
I also saw that there are different ways to do this. Is One Method Better Than Another? Or is it just a matter of taste?
The choice to use = or not is stylistic when using curly brackets. Attempting to initialise without = and parentheses instead of curlies ends up being a function declaration for some cases, so you need to disambiguate by using = or curlies.
Curly brackets affect the form of initialisation in some cases. In cases where curlies and no curlies invoke the same constructor, using curlies is recommended because that syntax don't allow narrowing conversions. When curlies invoke a different constructor than no curlies, use the form that does what you need.
These apply to all initialisation; not just default members.
Related
I want to detect during compile time (static assertion) whether a class meets both the following conditions:
Has an implicit default constructor (i.e., no user-defined default constructor).
Has at least one data member which is a pod (i.e., a member whose default initialization is to assume whatever random bytes was in its memory address).
[I hope I used the term pod correctly here]
The idea is to avoid working with objects with uninitialized members. I know there are different methods to do this during coding, but I also want a mechanism to detect this during compilation.
I tried using different std/boost functions, such as is_trivially_constructible, is_pod, but none of these provide the exact terms I need.
For example, let's say I have the following classes:
struct A
{
int a;
}
struct B
{
int* b;
}
struct C
{
bool c;
std::string c_str_;
}
struct D
{
D();
float d;
}
struct E
{
std::string e;
}
Assuming the function I need is called "has_primitive_and_implicit_ctor", I would like the output for each call to be as in the comments:
has_primitive_and_implicit_ctor<A>(); //true - A has at least one pod type member (int)
has_primitive_and_implicit_ctor<B>(); //true - A has at least one pod type member (pointer)
has_primitive_and_implicit_ctor<C>(); //true - A has at least one pod type member (bool), even though there is one non-pod member
has_primitive_and_implicit_ctor<D>(); //false - has a pod member(float), but a user defined ctor
has_primitive_and_implicit_ctor<E>(); //false - doesn't have a default ctor but has no pod members
Firstly, it seems to me like a broken design to expect from the user of a class to care about its member initialisation. You should make sure in the class itself that all its members are initialised, not somewhere else where it is used.
What you are looking for does not exist, and if it would, it would not even help you. The existence of an explicit constructor does not guarantee that a data member is initialised. On the other hand, with C++11 it is even possible to initialise data members without explicitly writing a constructor (using the brace syntax in the class declaration). Also you just seem to care about uninitialised POD members, but what about uninitialised non-POD members?
That said, compiler can generate warnings about uninitialised values, but often you have to enable this warning (e.g. -Wuninitialized option for gcc). Most compilers allow to force treating warnings as an error. In combination this can give you the desired effect even without specifically writing code to test for it, and it would also work for any uninitialised values, not only those in classes. Maybe this is the solution you are looking for.
I am writing a C++ application that makes use of plenty of child objects nested within one 'root' object.
Each of these needs to be initialized in a specific order, with various operations being done between each initialization, and sometimes needing to have previously-initialized ones as arguments to each other.
However, my compiler is forcing me to initialize these in the constructor's initializer list, insisting that initializing within the constructor is not enough. For example, I could not do the following:
SomeThing::SomeThing() {
int argGottenByLibraryCall;
someLibraryCallToGetArg(&argGottenByLibraryCall);
m_ChildObject = ChildClass(argGottenByLibraryCall);
}
I have taken to implementing a post-creation initializer function instead:
SomeThing::SomeThing() : m_ChildObject() {
int argGottenByLibraryCall;
someLibraryCallToGetArg(&argGottenByLibraryCall);
m_ChildObject.Initialize(argGottenByLibraryCall);
}
This, however, seems like a poor practice for me to follow. Is there a better way of making my compiler (VC++ 2017) accept initialization within the constructor body?
This, however, seems like a poor practice for me to follow.
The poor practice is not using initialization lists. They allow you to mark your data members as const and also ensure that they are initialized.
The correct way to solve your problem is to restructure your code so that m_ChildObject has a proper constructor that can be used in the member initialization list.
If that is not possible, wrap your initialization logic in a function and use that in the member initialization list:
ChildObjectType makeChildObject() {
int argGottenByLibraryCall;
someLibraryCallToGetArg(&argGottenByLibraryCall);
ChildObjectType result;
result.Initialize(argGottenByLibraryCall);
return result;
}
// ...
SomeThing::SomeThing() : m_ChildObject(makeChildObject()) { }
If I have a class:
class className{
int i;
public:
className(int value);
};
What is considered as the best practise for initializing the class variable 'i' from the constructor as per the below choices?
1) Use the actual field name with an underscore:
className::className(int i_){
i = i_;
}
2) Use the actual field name with "this":
className::className(int i){
this->i = i;
}
3) Completely inconsistent things like:
className::className(int value){
i = value;
}
I have seen this question being directly addressed for Java but not so much for C++. I ask because I would favor number 2 as I would personally prefer less variable names being made. However I would like to know what further considerations this could mean for the compiler or linker etc. I would also like to stick with the C++ norm.
Many Thanks!
Yes that's ok.
Some people actually think it idiomatic.
However, your samples all lack the use of initializer lists :)
class className{
int i;
public:
className(int value) : i(value) {};
};
I suggest to avoid the confusion with duplicate names. It makes the compiler complain if you accidentally mess up.
The best practice is to initialize your member variables in the initializer list:
className::className(int i_) : i(i_){}
^^^^^
Reasons:
Performance: You avoid unnecessary calls to members' default constructors.
Having Members not default constructible: If you have member variables that aren't default constructible (i.e., they don't have a default constructor), you are obliged to initialize them in the initializer list.
Having Members const-qualified: Same as 2.
Having Members references to objects: Same as 2.
Readability: Opinion based.
Extensibility: Opinion based.
As far as it concerns the naming issue: IMHO, it's primarily opinion based. Personally, for parameters of a constructor I use the suffix underscore as well.
I am in agreement with #sehe, to clarify on his context of initializer lists:
className::className(int i_) : i(i_) {}
However! I think the identifier names are backwards in terms of appropriateness. i_ should be the private member variable, and i should be the constructor parameter.
My notes on each "choice":
1) It's easy to see which parameters correspond with one another here
2) It's explicitness here
3) I think you've already concluded your opinion on this one by wording it 'Completely Inconsistent' :).
I have a class Thing sporting no default constructor.
Now we define another class, which now has to initalise the array elements at once, as without a default constructor, no late assignment can be made. So we have:
class TwoThings
{
public:
Thing things[2];
TwoThings() : things({Thing("thing 1"),Thing("thing 2")})
{
}
}
Is this the correct way?
GCC compiles it fine, while Clang does not, stating an "initializer list" should be used. I tried several alternative ways like double braces {{ ... }} and such, but can't manage to get a compiling equivalent for Clang.
How to initialise arrays without default constructor in Clang?
Yes, parenthesised member array initialization is a GCC extension. To make it standard, you can just use a single set of braces (requires C++11):
TwoThings() : things{Thing("thing 1"),Thing("thing 2")}
{
}
If you can't use C++11, you might want to use a different storage method, like std::pair<Thing,Thing> or std::vector<Thing>.
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;
};