In C++11, we have two ways to initialize the data members of a class/struct as illustrated in the following examples:
struct A
{
int n = 7;
};
struct B
{
int n;
B() : n(7) {}
};
Question 1:
Which way is better?
Question 2:
Is the traditional way (the latter) not encouraged from the view of a modern-C++-style checker?
You can actually mix both styles. This is useful if you have multiple constructors, but the variables is only specifically initialized by one or a few of the constructors.
Example
struct A
{
int n = 7;
A() {} // n will be initialized to 7
A(int n_): n{n_} {} // Initialize n to something else
};
I am not sure, but I think that the first case is possible only with C++ primitive types. In most of the books, especially in book 55 Ways to improve your C++ code by Scott Meyers, it is recommended to go via first way, so I would stick with that. :-)
Don't forget, that order of evaluation and initialization is determined how members in classes are sorted.
I prefer just the second style of initialization.
Neither way is better, however, the new uniform initialization has the perk of being similar to other languages and over-all more understandable. Uniform initialization does not only apply to struct members, but also across the board for initializer lists and constructor arguments.
Related
I know below three styles of initializing data members of a c++ class. But which one is safer and recommended to use. Kindly tell me why?
Style-1
class example{
int var1 = 0;
double *var2 = NULL;
example()
{}
};
Style-2
class example{
int var1;
double *var2;
example()
{
var1 = 0;
var2 = NULL;
}
};
Style-3
class example{
int var1;
double *var2;
example():var1(0),var2(NULL)
{}
};
This is hard to answer right as for a "best practices" question like this, you will always get several opinions.
I would recommend to follow the C++ Core Guidelines when unsure what is a best practice. Regarding your topic see C.48 and C.49:
Prefer Style 1 over Styles 2,3
Prefer Style 3 over Style 2
To shortly recap the reasoning from my perspective:
Style 1 allows to use default constructors (not implementing a constructor, but still getting initialization)
Style 1 allows the reader of the header to see the defaults
With style 1, you only need to look at one place to ensure a variable is properly initialized and you cannot "forget" to initialize a variable in one of your constructors
Style 3 ist still needed when arguments are used to initialize variables. It is still to be preferred over style 2 as "initialization" of a variable is clearly communicated through initialization, at the expected position in the code, instead of being slightly obscured as an assignment operation that might be buried within the constructor code
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.
After reading up on C++11 and common guidelines surrounding it, I often read about how you should use in-class initialization as well as aggregate initialization.
Here's an example from what seems to be the "old" way of doing things:
class Example
{
public:
// Set "m_x" to "x", "m_y" gets set to the default value of 5
Example(int x) : m_x(x), m_y(5)
{
}
private:
int m_x;
int m_y;
};
And to my understanding this is what people recommend now:
class Example
{
public:
Example(int x) : m_x{x}
{
}
private:
int m_x{0}; // Supposedly {} works too? I guess this would
// only be necessary if I had another constructor
// taking in 0 arguments, so "m_x" doesn't go uninitialized
int m_y{5};
};
My question is: How does this affect pointers, references, and some of the STL classes? What's the best practice for those? Do they just get initialized with {}? Additionally, should I be doing this even if the constructor initializes the variables anyway? (i.e. Writing m_x{} even though it gets set to something else by the constructor anyway)
Thank you.
You can use in-class member initialization and delegating constructors to reduce code duplication. See my answer to a related question: Refactoring with C++ 11.
Member variables of pointer types can be initialized to nullptr using in-class member initialization. Initializing pointers to something else using in-class member initialization does not seem to be useful. You'll have to judge it for your specific use case.
Member variables of reference types will most likely need to be initialized using the initializer list syntax. Initializing references to something else using in-class member initialization does not seem to be useful. You'll have to judge it for your specific use case.
Re. classes from the standard library ... You can certainly initialize container types using in-class member initialization. The following class is perfectly fine.
struct Foo
{
std::vector<int> ar = {20};
};
This question already has answers here:
Order of member initialization list [duplicate]
(2 answers)
Closed 5 years ago.
All old and modern C++ books and experts state to initialize class members by their declaration order. But neither explains what if I don't??
I am not talking about classes with members of const types or smth.. just plain simple class.
Consider the sample:
class A
{
int n;
std::vector<double> VD;
char c;
public:
A():
VD(std::vector<double>(3)),
c('a'),
n(44)
{
}
};
Whats the difference of written code and the one with same order in which they are declared???
Whats the difference of written code and the one with same order in which they are declared???
If members don't depend on each other's initialization order, there is no difference whatsoever. But if they do, then a member initialization list may be telling a lie.
Many a programmer were bitten by this, when they thought their constructors were written correctly, but in fact they had undefined behavior on their hands.
Consider this simple case:
struct foo {
int _a;
int _b;
foo(int b) : _b(b), _a(2 * _b) {}
};
What's _a in the above example? If you answer anything but "the behavior is undefined because _b is used initialized", you'd be wrong.
But neither explains what if I don't?
Programmers have no control over it: the order in which you list members in the initialization list has no effect on the actual order of initialization. The compiler ignores the order of items on the list, and re-orders the expressions to match declaration order.
Here is a short example to illustrate this point:
struct Foo {
Foo(const char *s) { cout << "Init " << s << endl; }
};
struct Bar {
Foo a;
Foo b;
Foo c;
Bar() : c("c"), b("b"), a("a") {
}
};
The above prints
Init a
Init b
Init c
even though initialization lists the items in opposite order.
Demo.
There ought to be absolutely no difference in the generated assembly, although the "as-if" rule might get in the way.
Conceptually at least, n is initialised before c.
Reference: http://en.cppreference.com/w/cpp/language/as_if
You can't change initialisation order - it's the order the members appear in the class - the order in the initialisation list is not significant, though compilers may warn if the two orders don't match up.
I think there are two reasons to order them properly.
The same order as they are declared makes the code more readable, especially when you want to add or remove some more variables.
The order they are declared indicates their order in the memory. You have more locality when you initialize the variables.
It depends on how the members are used. If there is a dependency then order must be followed.
Consider below example.
class x{
size_t n;
char * ch; // the size of dynamic char array depends on n
}
Here, initializing in different order will result in undefined behavior
Other than this reason, of course readability and uniformity matters from coding guidelines POV.
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' :).