Say I have this class:
//Awesome.h
class Awesome
{
public:
Awesome();
private:
membertype member;
}
//Awesome.cpp
#include "Awesome.h"
Awesome::Awesome()
:member()
{
}
If I omit the member() in the initialization list of the constructor of Awesome, will the constructor of member be called automatically? And is it only called when I don't include member in the initialization list?
Yes. When a variable is not given in the initalizer list, then it is default constructed automatically.
Default contruction means, that if membertype is a class or struct, then it will be default contructed, if it's a built-in array, then each element will be default constructed and if it's a build-in type, then no initialization will be performed (unless the Awesome object has static or thread-local storage duration). The last case means that the member variable can (and often will) contain unpredictable garbage in case the Awesome object is created on the stack or allocated on the heap.
From § 8.5
If no initializer is specified for an object, the object is
default-initialized; if no initialization is performed, an object with
automatic or dynamic storage duration has indeterminate value. [ Note:
objects with static or thread storage duration are zero-initialized,
see 3.6.2. —end note ]
Update for future references: Further the meaning of default initialized is defined as
To default-initialize an object of type T means: — if T is a
(possibly cv-qualified) class type (Clause 9), the default constructor
for T is called (and the initialization is ill-formed if T has no
accessible default constructor); — if T is an array type, each
element is default-initialized; — otherwise, no initialization is
performed. If a program calls for the default initialization of
an object of a const-qualified type T, T shall be a class type with a
user-provided default constructor.
Further it varies from value initialized referring this:-
To value-initialize an object of type T means: — if T is a
(possibly cv-qualified) class type (Clause 9) with a user-provided
constructor (12.1), then the default constructor for T is called (and
the initialization is ill-formed if T has no accessible default
constructor); — if T is a (possibly cv-qualified) non-union class
type without a user-provided constructor, then the object is
zero-initialized and, if T’s implicitly-declared default constructor
is non-trivial, that constructor is called. — if T is an array
type, then each element is value-initialized; — otherwise, the
object is zero-initialized.
Related
I am trying to understand the exact behavior of value initialization by T() or T{} for a class type T in C++11.
What confuses me are these two snippets taken from http://en.cppreference.com:
Value Initialization:
The effects of value initialization are:
[...]
1) if T is a class type with no default constructor or with a user-provided or deleted default constructor, the object is default-initialized;
(since C++11)
[...]
so I looked up Default-Initialization:
The effects of default initialization are:
if T is a [...] class type, the constructors are considered and subjected to overload resolution against the empty argument list. The constructor selected (which is one of the default constructors) is called to provide the initial value for the new object;
[...]
So this basically says that if T is a class type and its implicit default constructor is not available, then the object will be constructed by a call to one of its default constructors? In my understanding, this makes only sense for the mentioned case of a user-provided default constructor; then, upon construction, only what is explicitly stated in that constructor will be executed, and every member not explicitly initialized will get default-initialized (please correct me if I am wrong here).
My questions:
1) What would happen if there was no user-provided default constructor and there was no default constructor or it was deleted? I would guess the code would not compile. If this is right, then:
2) What is the need to also explicitly mention the cases "no default constructor" and "deleted default constructor"?
The wording on cppreference doesn't seem to match that in the standard. C++11 8.5/7 [dcl.init]:
To value-initialize an object of type T means:
if T is a (possibly cv-qualified) class type (Clause 9) with a user-provided constructor (12.1), then the
default constructor for T is called (and the initialization is ill-formed if T has no accessible default
constructor);
if T is a (possibly cv-qualified) non-union class type without a user-provided constructor, then the object
is zero-initialized and, if T’s implicitly-declared default constructor is non-trivial, that constructor is
called.
if T is an array type, then each element is value-initialized;
otherwise, the object is zero-initialized.
An object that is value-initialized is deemed to be constructed and thus subject to provisions of this International
Standard applying to “constructed” objects, objects “for which the constructor has completed,” etc.,
even if no constructor is invoked for the object’s initialization.
For comparison, this is the wording in C++14 (n4140) 8.5/7 [dcl.init]:
To value-initialize an object of type T means:
if T is a (possibly cv-qualified) class type (Clause 9) with either no default constructor (12.1) or a
default constructor that is user-provided or deleted, then the object is default-initialized;
if T is a (possibly cv-qualified) class type without a user-provided or deleted default constructor, then
the object is zero-initialized and the semantic constraints for default-initialization are checked, and if
T has a non-trivial default constructor, the object is default-initialized;
if T is an array type, then each element is value-initialized;
otherwise, the object is zero-initialized.
An object that is value-initialized is deemed to be constructed and thus subject to provisions of this International
Standard applying to “constructed” objects, objects “for which the constructor has completed,” etc.,
even if no constructor is invoked for the object’s initialization.
Consider the following code:
class A {
public:
int i;
A() {}
};
class B {
public:
A a;
int i;
};
int main() {
B* p = new B {};
std::cout << p->i << " " << p->a.i << "\n";
}
Compiled with -std=c++11 in clang++, p->i turns out to be zero, but p->a.i doesn't. Shouldn't the whole object be zeroed as long as its class doesn't have user-provided constructor?
EDIT: Since there are some extensive discussion in the comments, I think it's better to add some excerpt from the standard here:
To value-initialize an object of type T means:
if T is a (possibly cv-qualified) class type (Clause 9) with a user-provided constructor (12.1), then the default constructor for T is called (and the initialization is ill-formed if T has no accessible default constructor);
if T is a (possibly cv-qualified) non-union class type without a user-provided constructor, then the object is zero-initialized and, if T’s implicitly-declared default constructor is non-trivial, that constructor is called.
if T is an array type, then each element is value-initialized;
otherwise, the object is zero-initialized.
To zero-initialize an object or reference of type T means:
if T is a scalar type (3.9), the object is set to the value 0 (zero), taken as an integral constant expression, converted to T;
if T is a (possibly cv-qualified) non-union class type, each non-static data member and each base-class subobject is zero-initialized and padding is initialized to zero bits;
if T is a (possibly cv-qualified) union type, the object’s first non-static named data member is zero-initialized and padding is initialized to zero bits;
if T is an array type, each element is zero-initialized;
if T is a reference type, no initialization is performed.
The second bullet of each applies here.
Clang is correct, per the C++11 standard plus relevant DRs
In the original C++11 specification, B{} would perform value-initialization, resulting in a.i being zero-initialized. This was a change in behavior compared to C++98 for cases like
B b = {};
... which were handled as aggregate initialization in C++98 but treated as value-initialization in C++11 FDIS.
However, the behavior in this case was changed by core issue 1301, which restored the C++98 behavior by mandating that aggregate initialization is used whenever an aggregate is initialized by a braced-init-list. Since this issue is considered a DR, it is treated as de facto applying to earlier revisions of the C++ standard, so a conforming C++11 compiler would be expected to perform aggregate initialization here rather than value-initialization.
Ultimately, it's a bad idea to rely on value-initialization to initialize your data members, especially for a class that has user-provided constructors.
It does indeed look like a bug (or, as pointed out in the comments, behaving according to C++03 despite specifying C++11). In C++11, value-initialisation should zero the members of a before calling its default constructor. Initialisation of B is governed by this rule of 8.5/7
if T is a (possibly cv-qualified) non-union class type without a user-provided constructor, then the object is zero-initialized and, if T’s implicitly-declared default constructor is non-trivial, that constructor is called.
The zero-initialisation should recursively zero-initialise a per this rule of 8.5/5
if T is a (possibly cv-qualified) non-union class type, each non-static data member and each base-class subobject is zero-initialized
and, of course, zero-initialisation of a should set i to zero.
It is not a compiler bug, it is a bug in your code. The compiler seems to be implementing the C++03 behaviour, but this has crucially changed in C++11.
These are some relevant quotes from the C++03 and C++11 standards
In C++03:
To value-initialize an object of type T means:
— if T is a class type
(clause 9) with a user-declared constructor (12.1), then the default
constructor for T is called (and the initialization is ill-formed if T
has no accessible default constructor);
— if T is a non-union class
type without a user-declared constructor, then every non-static data
member and base-class component of T is value-initialized;
(emphasis mine)
In C++11:
To value-initialize an object of type T means:
— if T is a (possibly
cv-qualified) class type (Clause 9) with a user-provided constructor
(12.1), then the default constructor for T is called (and the
initialization is ill-formed if T has no accessible default
constructor);
— if T is a (possibly cv-qualified) non-union class type
without a user-provided constructor, then the object is
zero-initialized and, if T’s implicitly-declared default constructor
is non-trivial, that constructor is called.
and
To zero-initialize an object or reference of type T means:
— if T is a
scalar type (3.9), the object is set to the value 0 (zero), taken as
an integral constant expression, converted to T;
if T is a
(possibly cv-qualified) non-union class type, each non-static data
member and each base-class subobject is zero-initialized and padding
is initialized to zero bits;
Note: The following only applies to C++03:
Either remove A's user-provided constructor, or change it to
A() : i() {}
When you value-initialize a B here,
B* p = new B {};
it value-initializes its data members. Since A has a default constructor, the value-initialization results in a call to that. But that constructor does not explicitly initialize A::i, so it gets default-initialized, which for an int means no initialization is performed.
If you had not provided a default constructor for A, then the data member would get zero-initialized when an A is value-initialized.
Integral types are not required to be initialized to a value like that in a non-default constructor (since you have provided a constructor)
Change your constructor to A() : i(0) {}.
Does the C++ standard guarantee that uninitialized POD members retain their previous value after a placement new?
Or more precisely, will the following assert always be satisfied according to C++11?
#include <cstdlib>
#include <cassert>
struct Foo {
int alpha; // NOTE: Uninitialized
int beta = 0;
};
int main()
{
void* p = std::malloc(sizeof (Foo));
int i = some_random_integer();
static_cast<Foo*>(p)->alpha = i;
new (p) Foo;
assert(static_cast<Foo*>(p)->alpha == i);
}
Is the answer the same for C++03?
Does the C++ standard guarantee that uninitialized POD members retain their previous value after a placement new?
Will the following assert always be satisfied according to C++11?
No.
Uninitialized data members have an indeterminate value, and this is not at all the same as saying that the underlying memory is left alone.
[C++11: 5.3.4/15]: A new-expression that creates an object of type T initializes that object as follows:
If the new-initializer is omitted, the object is default-initialized (8.5); if no initialization is performed, the object has indeterminate value.
Otherwise, the new-initializer is interpreted according to the initialization rules of 8.5 for direct-initialization.
[C++11: 8.5/6]: To default-initialize an object of type T means:
if T is a (possibly cv-qualified) class type (Clause 9), the default constructor for T is called (and the initialization is ill-formed if T has no accessible default constructor);
if T is an array type, each element is default-initialized;
otherwise, no initialization is performed.
[C++11: 12.1/6]: A default constructor that is defaulted and not defined as deleted is implicitly defined when it is odr-used (3.2) to create an object of its class type (1.8) or when it is explicitly defaulted after its first declaration. The implicitly-defined default constructor performs the set of initializations of the class that would be
performed by a user-written default constructor for that class with no ctor-initializer (12.6.2) and an empty compound-statement.
[C++11: 12.6.2/8]: In a non-delegating constructor, if a given non-static data member or base class is not designated by a mem-initializer-id (including the case where there is no mem-initializer-list because the constructor has no ctor-initializer) and the entity is not a virtual base class of an abstract class (10.4), then
if the entity is a non-static data member that has a brace-or-equal-initializer, the entity is initialized as specified in 8.5;
otherwise, if the entity is a variant member (9.5), no initialization is performed;
otherwise, the entity is default-initialized (8.5).
(NB. the first option in 12.6.2/8 is how your member beta is handled)
[C++11: 8.5/6]: To default-initialize an object of type T means:
if T is a (possibly cv-qualified) class type (Clause 9), the default constructor for T is called (and the initialization is ill-formed if T has no accessible default constructor);
if T is an array type, each element is default-initialized;
otherwise, no initialization is performed.
[C++11: 8.5/11]: If no initializer is specified for an object, the object is default-initialized; if no initialization is performed, an object with automatic or dynamic storage duration has indeterminate value.
A compiler could choose to zero-out (or otherwise alter) the underlying memory during allocation. For example, Visual Studio in debug mode is known to write recognisable values such as 0xDEADBEEF into memory to aid debugging; in this case, you're likely to see 0xCDCDCDCD which they use to mean "clean memory" (reference).
Will it, in this case? I don't know. I don't think that we can know.
What we do know is that C++ doesn't prohibit it, and I believe that brings us to the conclusion of this answer. :)
Is the answer the same for C++03?
Yes, though through slightly different logic:
[C++03: 5.3.4/15]: A new-expression that creates an object of type T initializes that object as follows:
If the new-initializer is omitted:
If T is a (possibly cv-qualified) non-POD class type (or array thereof), the object is default-initialized (8.5). If T is a const-qualified type, the underlying class type shall have a user-declared default constructor.
Otherwise, the object created has indeterminate value. If T is a const-qualified type, or a (possibly cv-qualified) POD class type (or array thereof) containing (directly or indirectly) a member of const-qualified type, the program is ill-formed;
If the new-initializer is of the form (), the item is value-initialized (8.5);
If the new-initializer is of the form (expression-list) and T is a class type, the appropriate constructor is called, using expression-list as the arguments (8.5);
If the new-initializer is of the form (expression-list) and T is an arithmetic, enumeration, pointer, or pointer-to-member type and expression-list comprises exactly one expression, then the object is initialized to the (possibly converted) value of the expression (8.5);
Otherwise the new-expression is ill-formed.
Now, all that was my strict interpretation of the rules of initialisation.
Speaking practically, I think you're probably correct in seeing a potential conflict with the definition of placement operator new syntax:
[C++11: 18.6.1/3]: Remarks: Intentionally performs no other action.
An example that follows explains that placement new "can be useful for constructing an object at a known address".
However, it doesn't actually talk about the common use of constructing an object at a known address without mungling the values that were already there, but the phrase "performs no other action" does suggest that the intention is that your "indeterminate value" be whatever was in memory previously.
Alternatively, it may simply prohibit the operator itself from taking any action, leaving the allocator free to. It does seem to me that the important point the standard trying to make is that no new memory is allocated.
Regardless, accessing this data invokes undefined behaviour:
[C++11: 4.1/1]: A glvalue (3.10) of a non-function, non-array type T can be converted to a prvalue. If T is an incomplete type, a program that necessitates this conversion is ill-formed. If the object to which the glvalue refers is not
an object of type T and is not an object of a type derived from T, or if the object is uninitialized, a program that necessitates this conversion has undefined behavior. If T is a non-class type, the type of the prvalue is the cv-unqualified version of T. Otherwise, the type of the prvalue is T.
So it doesn't really matter: you couldn't compliantly observe the original value anyway.
C++11 12.6.2/8 "Initializing bases and members" says:
In a non-delegating constructor, if a given non-static data member or
base class is not designated by a mem-initializer-id (including the
case where there is no mem-initializer-list because the constructor
has no ctor-initializer) and the entity is not a virtual base class of
an abstract class (10.4), then
if the entity is a non-static data member that has a brace-or-equal-initializer, the entity is initialized as specified in
8.5;
otherwise, if the entity is a variant member (9.5), no initialization is performed;
otherwise, the entity is default-initialized (8.5).
Default initialization on an int does nothing (8.5/6 "Initializers"):
To default-initialize an object of type T means:
if T is a (possibly cv-qualified) class type (Clause 9), the default constructor for T is called (and the initialization is
ill-formed if T has no accessible default constructor);
if T is an array type, each element is default-initialized;
otherwise, no initialization is performed.
So the member alpha should be left alone.
This compiles perfectly fine with the current MSVC compiler:
struct Foo
{
} const foo;
However, it fails to compile with the current g++ compiler:
error: uninitialized const 'foo' [-fpermissive]
note: 'const struct Foo' has no user-provided default constructor
If I provide a default constructor myself, it works:
struct Foo
{
Foo() {}
} const foo;
Is this another case of MSVC being too permissive, or is g++ too strict here?
The C++03 Standard:
8.5 [dcl.init] paragraph 9
If no initializer is specified for an object, and the object is of (possibly cv-qualified) non-POD class type (or array thereof), the object shall be default-initialized; if the object is of const-qualified type, the underlying class type shall have a user-declared default constructor.
From the above the error in gcc seems to be perfectly valid.
[2003: 8.5/9]: If no initializer is specified for an object, and the
object is of (possibly cv-qualified) non-POD class type (or array
thereof), the object shall be default-initialized; if the object is of
const-qualified type, the underlying class type shall have a
user-declared default constructor. Otherwise, if no initializer is
specified for a nonstatic object, the object and its subobjects, if
any, have an indeterminate initial value; if the object or any of
its subobjects are of const-qualified type, the program is ill-formed.
And:
[n3290: 8.5/11]: If no initializer is specified for an object, the object is default-initialized; if no initialization is
performed, an object with automatic or dynamic storage duration has
indeterminate value. [ Note: Objects with static or thread storage
duration are zero-initialized, see 3.6.2._ —end note_ ]
[n3290: 8.5/6]: To default-initialize an object of type T means:
if T is a (possibly cv-qualified) class type (Clause 9), the default constructor for T is called (and the initialization is ill-formed if T has no accessible default constructor);
if T is an array type, each element is default-initialized;
otherwise, no initialization is performed.
If a program calls for the default initialization of an object of a const-qualified type T, T shall be a class type with a user-provided default constructor.
So MSVC is more permissive here than both standards mandate.
I don't know the exact wording of the standard, but the error in g++ seems quite more sensible than the option of not saying anything. Consider this:
struct X {
int value;
};
const X constant; // constant.value is undefined
Not in the case of a user provided default constructor (even if it does nothing) the compiler will call that constructor and the object will be initialized (by whatever definition of initialized you have implemented in your constructor).
C++17 Update
C++17 adds some nuance to the requirement that const-qualified class types have a default constructor. The standard now defines the "const-default-constructable" concept:
7 To default-initialize an object of type T means:
(7.1) — If T is a (possibly cv-qualified) class type, constructors are considered. The applicable constructors are enumerated, and the best one for the initializer() is chosen through overload resolution. The constructor thus selected is called, with an empty argument list, to initialize the
object.
(7.2) — If T is an array type, each element is default-initialized.
(7.3) — Otherwise, no initialization is performed.
A class type T is const-default-constructible if default-initialization of T would invoke a user-provided constructor of T (not inherited from a base class) or if
(7.4) — each direct non-variant non-static data member M of T has a default member initializer or, if M is of class type X (or array thereof), X is const-default-constructible,
(7.5) — if T is a union with at least one non-static data member, exactly one variant member has a default member initializer,
(7.6) — if T is not a union, for each anonymous union member with at least one non-static data member (if any), exactly one non-static data member has a default member initializer, and
(7.7) — each potentially constructed base class of T is const-default-constructible.
If a program calls for the default-initialization of an object of a const-qualified type T, T shall be a const-default-constructible class type or array thereof.
I had always thought that creating a new object would always call the default constructor on an object, and whether the constructor was explicit or automatically generated by the compiler made no difference. According to this highly regarded answer to a different question, this changed in a subtle way between C++98 and C++03 and now works like so:
struct B { ~B(); int m; }; // non-POD, compiler generated default ctor
new B; // default-initializes (leaves B::m uninitialized)
new B(); // value-initializes B which zero-initializes all fields since its default ctor is compiler generated as opposed to user-defined.
Can anyone tell me:
Why was the standard changed, i.e. what advantage does this give or what is now possible that wasn't before;
What exacly do the terms "default-initialize" and "value-initialize" represent?
What's the relevant part of the standard?
I do not know what the rationales around the change (or how the standard was before), but on how it is, basically default-initialization is either calling a user defined constructor or doing nothing (lots of hand-waving here: this is recursively applied to each subobject, which means that the subobjects with a default constructor will be initialized, the subobjects with no user defined constructors will be left uninitialized).
This falls within the only pay for what you want philosophy of the language and is compatible with C in all the types that are C compatible. On the other hand, you can request value-initialization, and that is the equivalent to calling the default constructor for objects that have it or initializing to 0 converted to the appropriate type for the rest of the subobjects.
This is described in §8.5 Initializers, and it is not trivial to navigate through. The definitions for zero-initialize, default-initialize and value-initialize are the 5th paragraph:
To zero-initialize an object of type T means:
— if T is a scalar type (3.9), the object is set to the value of 0 (zero) converted to T;
— if T is a non-union class type, each nonstatic data member and each base-class subobject is zeroinitialized;
— if T is a union type, the object’s first named data member89) is zero-initialized;
— if T is an array type, each element is zero-initialized;
— if T is a reference type, no initialization is performed.
To default-initialize an object of type T means:
— if T is a non-POD class type (clause 9), the default constructor for T is called (and the initialization is ill-formed if T has no accessible default constructor);
— if T is an array type, each element is default-initialized;
— otherwise, the object is zero-initialized.
To value-initialize an object of type T means:
— if T is a class type (clause 9) with a user-declared constructor (12.1), then the default constructor for T is called (and the initialization is ill-formed if T has no accessible default constructor);
— if T is a non-union class type without a user-declared constructor, then every non-static data member and base-class component of T is value-initialized;
— if T is an array type, then each element is value-initialized;
— otherwise, the object is zero-initialized
A program that calls for default-initialization or value-initialization of an entity of reference type is illformed. If T is a cv-qualified type, the cv-unqualified version of T is used for these definitions of zeroinitialization, default-initialization, and value-initialization.