We know that in the following code
class Foo1 {
private:
int i;
bool b;
public:
Foo1() : i(7), b(false) {}
};
"i" is going to be init before "b". If I try to init "b" before "i", I'll get a warning.
what about this case:
class Foo2 {
private:
int i;
private:
bool b;
public:
// what happens if b is first because compiler reordered?
Foo2() : b(false), i(7) {}
};
?
We know that the compiler is free to order "i" and "b" since they are in separate access specifiers.
So what is the order of initialization in this case?
anything guaranteed like in the previous simple case?
The order of initialization is guaranteed; i is always initialized before b. Non-static data members are initialized in the order of their declaration in the class definition, regardless of their access specifiers.
[class.base.init]/13.3
Then, non-static data members are initialized in the order they were declared in the class definition (again regardless of the order of the mem-initializers).
Related
I'd like to know if there is a difference between this code:
class Foo{
private:
int a = 0;
public:
Foo(){}
}
And:
class Foo{
private:
int a;
public:
Foo(): a(0) {}
}
And, if so, which should be preferred?
I know it's preferable to use an initialiser list than assigning in the constructor body, but what about initialiser list vs directly initialising in field declaration (for primitive types, at least, as is the case here)?
Also, what of the case below:
class Foo{
private:
int a = 0;
public:
Foo(){}
Foo(int i): a(i) {}
}
When the non-default constructor is called: is "a" initialised twice, first to 0 then to "i", or directly to "i"?
From cppreference - Non-static data members
Member initialization
1) In the member initializer list of the constructor.
2) 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.
To conclude, both initializers are equivalent and do what they are supposed to do.
I would prefer the default member initializer, if I'd use the default constructor anyway, or if all or most constructors would initialize the member to the same value.
class Foo {
private:
int a = 0;
};
If all constructors initialize the member to some different value however, using the default member initializer makes less sense, and then an explicit initialization in the respective constructors would be more clear
class Foo {
private:
int a;
public:
Foo() : a(3) {}
Foo(int i) : a(i) {}
};
The first set of examples are identical to each other.
For the last example, the C++ standard specifies as follows:
12.6.2 Initializing bases and members
[ ... ]
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-equal-initializer will not take
place. — end example ]
The two are identical.
One rule of software engineering is DRY -- don't repeat yourself. DRY states that if you can avoid repeating the same token twice, or having two identical lists, you should.
This is for a few reasons. Maintaining two identical lists is surprisingly error prone; one gets modified, or has a typo, and the other does not. It makes code longer, which can make it harder to read. And avoiding copy-paste coding encourages using some very powerful and expressive techniques that can make what you are doing clearer than doing it manually 17 times.
struct foo {
int a;
foo():a(7) {}
};
here we have repeated ourselves -- the list of member variables, in particular, is listed twice. Once in the definition of foo, and again in the initializer list of foo::foo. If it is missing somewhere, you get uninitialized data.
struct foo {
int a = 7;
foo() {}
};
Here we do not repeat ourselves.
struct foo {
int a = 7;
foo() {}
foo(int i):a(i) {}
};
Here there is some repetition, but the repetition is unavoidable. It is, however, minimized.
There is some cost here, because someone might interpret a=7 to mean "it always starts at 7", and not "the default is 7".
struct foo {
int a = 7;
foo():a(3) {}
foo(int i):a(i) {}
};
And the above is a horrible anti-pattern.
I am sure this question has been asked before. But I cannot seem to find the exact answer that I am looking for. Basically I am trying to create an object of the class as a member of the other class and pass one of the members by reference to the owned object through the constructor. Sometimes this seems to work, other times I get a random value.
I think that I am not understanding some rudimentary rule of initialization order
Here is the code example:
class Foo
{
public:
Foo();
private:
int b;
Bar c;
};
class Bar
{
public:
Bar(int& parm);
private:
int& b_ref;
};
Foo::Foo(): b(0), c(b)
{}
Bar::Bar(int& parm): b_ref(parm)
{}
What I want is for c to own a reference to b and be able see the value as it changes.
Should I not use the initialization list in this case?
The rule is that objects are initialised in the order of their declaration in the class. In this case, it means that b is initialised before c, so this code should always work correctly.
If you swapped the order of the b and c members, then the int referenced by param would not yet be initialised in the constructor of Bar.
class a
{
public:
a() : b(5), a1(10) //will firstly initialize a1 then b, so order here doesn't matter
int a1;
private:
int b;
}
The question is how to change the order (to have b initialized before a1)? I must have public members above private so that solution isn't okay for me. Of course here I use ints, the problem is more complex but it's just an example which shows what is my problem.
You cannot change the order of initialization, that is always defined by the order of declaration of the members in your class. This is necessary because the order of destruction must be the inverse of the order of construction, and if you changed the order of construction, the compiler would be forced to keep track of which order you have initialized your members in in order to generate proper destruction sequences.
So my advice is:
Just live with it, and;
Do not depend on the order of construction of your member variables.
To achieve point 2), you can provide default constructors for your members to do default initialization, and then initialize your members properly in the order you want inside the body of your constructor (in other words, decouple construction from logical initialization).
The order of initialization is determined by the order of declaration of the member variables. So if you want b to be initialized before a, you have to declare it before.
class a
{
public:
a() : b(5), a1(10) {}
private:
int b;
public:
int a1;
};
If I understand you correct you have some kind of style guide saying that public members should be before private.
In that case I would suggest you declare all your member variables private and create accessor functions to them instead. That way you get around it.
class a
{
public:
a() : _a1(5), _b(10)
int a1() const { return _a1; }
void a1(int value) { _a1 = value; }
int b() const { return _b; }
void b(int value) { _b = value; }
private:
int _a1;
int _b;
}
any sane compiler will anyway optimize it so the overhead will be minimal.
Make your b object private, declared it before a1, and make an accessor function for accessing the content of b. [If necessary, make it return a reference to the b object, so the calling code can modify it - although that is quite clearly bad design to expose the internals of a class to the calling code, whether it's through a public declaration or through returning a reference]
Is the order of the initializers for a class' constructor significant?
So say I have:
class MyClass : BaseClass
{
int a, b, c;
public:
MyClass(int);
}
e.g. 1:
MyClass::MyClass(int forBase) :
a(7),
b(14),
c(28),
BaseClass(forBase) { }
e.g. 2:
MyClass::MyClass(int forBase) :
BaseClass(forBase),
a(7),
b(14),
c(28) { }
Would example 1 do something different to example 2?
Would example 1 do something different to example 2?
No. Initialisation order is dictated by the standard, not by the order in which you write the initialisers:
[C++11: 12.6.2/10]: In a non-delegating constructor, initialization
proceeds in the following order:
First, and only for the constructor of the most derived class (1.8), virtual base classes are initialized in the order they appear on a depth-first left-to-right traversal of the directed acyclic graph of base classes, where “left-to-right” is the order of appearance of the base classes in the derived class base-specifier-list.
Then, direct base classes are initialized in declaration order as they appear in the base-specifier-list (regardless of the order of the mem-initializers).
Then, non-static data members are initialized in the order they were declared in the class definition (again regardless of the order of the mem-initializers).
Finally, the compound-statement of the constructor body is executed.
In fact, if you write them in any other order and one depends on the other, you may well be warned about it:
struct T {
std::vector<int> v;
int w;
T(int w) : w(w), v(0, w) {}
};
int main() {
T t(3);
}
// g++ 4.1.2:
// t.cpp: In constructor 'T::T(int)':
// Line 3: warning: 'T::w' will be initialized after
// Line 2: warning: '__gnu_debug_def::vector<int, std::allocator<int> > T::v'
// Line 5: warning: when initialized here
The order does not matter for the compiler (the initialization order is always base classes first, and always base classes in the order of derivation, and members in the order of declaration), but it does matter for the reader: It is very confusing if the order in which you give the initializers does not match the order in which they are executed. While in most cases it doesn't matter, in some cases you can create subtle bugs, e.g.
struct Derived: Base
{
int member;
Derived();
}
Derived::Derived():
member(3),
Base(member) // This is executed *before* member is initialized!
{
}
This bug would stand out more clearly if the initializers were given in the correct order:
Derived::Derived():
Base(member), // Now we see immediately that member is uninitialized
member(3),
{
}
It doesn't matter in which order you list the initializers in the constructor initialization list. Members are initialized in the order they are declared and base(s) are initialized before members.
However, listing initializers in a different order that that can bite you if a subobject's initial value depends on the values of other subobjects.
class A
{
int y, x;
A(int x_value): x(x_value), y(x) {}
};
Since y is initialized before x, it gets a garbage value, and the order of the initializer list just hides the bug. That's why this deserves a compiler warning.
Is order of execution in constructor initialization list determinable? I know that members order in a class is the order in which those members will be initialized but if I have scenario like this:
class X()
{
X_Implementation* impl_;
};
and then providing that allocator is available:
X::X():impl_(Allocate(sizeof(X_Implementation)))//HERE I'M ALLOCATING <--1
,impl_(Construct<X_Implementation>(impl_))//AND HERE I'M CONSTRUCTING <--2
{
}
but in order for this to be dependable this order MUST be from left to right. Is it guarantied by GREAT BOOK OF std:: or not? If not I can always move the second line into the body.
According to ISO/IEC 14882:2003(E) section 12.6.2:
Initialization shall proceed in the following order:
First, and only for the constructor of the most derived class as described below, virtual base classes shall
be initialized in the order they appear on a depth-first left-to-right traversal of the directed acyclic graph
of base classes, where “left-to-right” is the order of appearance of the base class names in the derived
class base-specifier-list.
Then, direct base classes shall be initialized in declaration order as they appear in the base-specifier-list
(regardless of the order of the mem-initializers).
Then, nonstatic data members shall be initialized in the order they were declared in the class definition
(again regardless of the order of the mem-initializers).
Finally, the body of the constructor is executed.
So, follow that order, and you'll have your order. Also according to the standard, the order is prescribed as such so that objects can be uninitialized in the precisely reverse order.
The C++ standard does guarantee an order for initialization lists (ISO C++ Standard 12.6.2/5):
...nonstatic data members shall be initialized in the order they were declared in the class definition (again regardless of the order of the mem-initializers).
(See Wyatt Anderson's answer for more information.)
Example:
class Foo
{
public:
Foo();
private:
A a;
B b;
C c;
};
Foo::Foo() : b(), a(), c() {
// a is initialized first, then b, then c - NOT b, a, then c!
}
However, you can't initialize a variable twice - what you have won't compile.
class X //() what's with the pair of parentheses you have in your code snippet?
{
public:
X();
private:
X_Implementation* impl_;
};
X::X():
impl_(Allocate(sizeof(X_Implementation))),
// It is not allowed to initialize a data member twice!
impl_(Construct<X_Implementation>(impl_)) {
}
Instead, just put the extra work into the constructor:
X::X() : impl_(Allocate(sizeof(X_Implementation))) {
impl_ = Construct<X_Implementation>(impl_);
}
There may be exception safety issues with the above code, but without knowing what Allocate() or Construct() actually does I'm not able to tell. I can tell you that it's best to separate allocation and construction into their own classes if you do that, using the Resource Acquisition Is Initialization (RAII) idiom:
class XBase
{
protected:
XBase() : impl_(Allocate(sizeof(X_Implementation))) { }
~XBase() {
if( !impl_) { Deallocate(impl_); } // Or something like this
}
X_Implementation* impl_;
};
class X : private XBase // XBase is an implementation detail
{
public:
X() {
impl_ = Construct<X_Implementation>(impl_);
}
~X() {
Destruct<X_Implementation>(impl_); // Or something like this
}
};
This way, if Construct() throws an exception, you won't leak memory since the base class destructor will be called which will deallocate the memory pointed by impl_. This is important because if the exception is not caught and leaves the constructor, its matching destructor will not be called. See Bjarne Stroustrup's paper on exception safety.
Your specific scenario is based on the idea of initializing the same member more than once. This is plain illegal in C++. Your code will not compile. So, the question you are asking doesn't really exist.
The order of member initialization is the order of their declaration in class definition. In no-inheritance contexts that covers everything related to the order of initialization in the constructions initializer list.