I only just learned yesterday that specifying parameters to initializer list items is optional. However, what are the rules for what happens in this case?
In the below example, will ptr be initialized to 0, toggle to false, and Bar default-constructed? I guess this question is sort of redundant, because there would be little point in initializer lists if unspecified argument values == undefined behavior.
Could I also be pointed to the section of the C++ standard that states the behavior in the case of initializer list items not being given arguments?
class Bar
{
Bar() { }
};
class SomeClass;
class AnotherClass
{
public:
SomeClass *ptr;
bool toggle;
Bar bar;
AnotherClass() : ptr(), toggle(), bar() { }
// as opposed to...
// AnotherClass() : ptr(NULL), toggle(false), bar(Bar()) { }
};
Yes, the members will be initialized to zero and a default-constructed object respectively.
The C++ 11 standard specifies this behavior in 12.6.2/7:
The expression-list or braced-init-list in a mem-initializer is used
to initialize the designated subobject (or, in the case of a
delegating constructor, the complete class object) according to the
initialization rules of 8.5 for direct-initialization.
In turn, 8.5/10 reads:
An object whose initializer is an empty set of parentheses, i.e., (),
shall be value-initialized.
Paragraph 8.5/7 defines value-initialized:
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.
And finally, 8.5/5 defines 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.
In the below example, will ptr be initialized to 0, toggle to false, and Bar default-constructed?
Yes. If a member initialiser appears in the initialiser list with empty parentheses, then that member is value initialised. This means that numerical types will be initialised to zero, pointers to null, and classes with default constructors using that constructor.
If you don't include the member in the initialiser list at all, then it will instead be default initialised; in that case. numerical and pointer types will be left uninitialised.
Could I also be pointed to the section of the C++ standard that states the behavior in the case of initializer list items not being given arguments?
C++11 12.6.2/7 specifies that the rules are the same as for direct initialisation.
C++11 8.5/16 specifies that if the initialiser is (), the object is value-initialised.
C++11 8.5/7 defines value initialisation.
Initialisations are covered in [dcl.init] (aka 8.5)
Point 10 says:
An object whose initializer is an empty set of parentheses, i.e., (), shall be value-initialized.
Value-initialisation is, put simply, default construction for classes and zero-initialisation for non-class types.
Related
I have templated gray_code class which is meant to store some unsigned integer whose underlying bits are stored in Gray code order. Here it is:
template<typename UnsignedInt>
struct gray_code
{
static_assert(std::is_unsigned<UnsignedInt>::value,
"gray code only supports built-in unsigned integers");
// Variable containing the gray code
UnsignedInt value;
// Default constructor
constexpr gray_code()
= default;
// Construction from UnsignedInt
constexpr explicit gray_code(UnsignedInt value):
value( (value >> 1) ^ value )
{}
// Other methods...
};
In some generic algorithm, I wrote something like this:
template<typename UnsignedInt>
void foo( /* ... */ )
{
gray_code<UnsignedInt> bar{};
// Other stuff...
}
In this piece of code, I expected bar to be zero-intialized and therefore bar.value to be zero-initialized. However, after having struggled with unexpected bugs, it appears that bar.value is initialized with garbage (4606858 to be exact) instead of 0u. That surprised me, so I went to cppreference.com to see what the line above was exactly supposed to do...
From what I can read, the form T object{}; corresponds to value initialization. I found this quote interesting:
In all cases, if the empty pair of braces {} is used and T is an aggregate type, aggregate-initialization is performed instead of value-initialization.
However, gray_code has a user-provided constructor. Therefore it is not an aggregate thus aggregate initialization is not performed. gray_code has no constructor taking an std::initializer_list so list initialization is not performed either. The value-initialized of gray_code should then follow the usual C++14 rules of value initialization:
1) If T is a class type with no default constructor or with a user-provided default constructor or with a deleted default constructor, the object is default-initialized.
2) If T is a class type without a user-provided or deleted default constructor (that is, it may be a class with a defaulted default constructor or with an implicitly-defined one) then the object is zero-initialized and then it is default-initialized if it has a non-trivial default constructor.
3) If T is an array type, each element of the array is value-initialized.
4) Otherwise, the object is zero-initialized.
If I read correctly, gray_code has an explicitly defaulted (not user-provided) default constructor, therefore 1) does not apply. It has a defaulted default constructor, so 2) applies: gray_code is zero-initialized. The defaulted default constructor seems to meet all the requirements of a trivial default constructor, so default initialization should not happen. Let's have a look then at how gray_code is zero-initialized:
If T is a scalar type, the object's initial value is the integral constant zero implicitly converted to T.
If T is an non-union class type, all base classes and non-static data members are zero-initialized, and all padding is initialized to zero bits. The constructors, if any, are ignored.
If T is a union type, the first non-static named data member is zero-initialized and all padding is initialized to zero bits.
If T is array type, each element is zero-initialized
If T is reference type, nothing is done.
gray_code is a non-union class type. Therefore, all of its non-static data members should be initialized which means that value is zero-initialized. value satisfies std::is_unsigned and is therefore a scalar type, which means that it should be initialized with "the integral constant zero implicitly converted to T".
So, if I read correctly all of that, in the function foo above, bar.value should always be initialized with 0 and it should never be initialized with garbage, am I right?
Note: the compiler I compiled my code with is MinGW_w4 GCC 4.9.1 with (POSIX threads and dwarf exceptions) in case that helps. While I sometimes get garbage on my computer, I never managed to get anything else than zero with online compilers.
Update: It seems to be a GCC bug that the error is mine and not that of my compiler. Actually, when writing this question, I assumed for the sake of simplicity that
class foo {
foo() = default;
};
and
class foo {
foo();
};
foo::foo() = default;
were equivalent. They are not. Here is the quote from the C++14 standard, section [dcl.fct.def.default]:
A function is user-provided if it is user-declared and not explicitly defaulted or
deleted on its first declaration.
In other words, when I got garbage values, my defaulted default constructor was indeed user-provided since it was not explicitly efaulted on its first declaration. Therefore, what happened was not zero initialization but default initialization. Thanks #Columbo again for pointing out the real problem.
So, if I read correctly all of that, in the function foo above,
bar.value should always be initialized with 0 and it should never be
initialized with garbage, am I right?
Yes. Your object is direct-list-initialized. C++14's* [dcl.init.list]/3 specifies that
List-initialization of an object or reference of type T is defined
as follows:
[… Inapplicable bullet points…]
Otherwise, if T is an aggregate, aggregate initialization is performed (8.5.1).
Otherwise, if the initializer list has no elements and T is a class type with a default constructor, the object is value-initialized.
[…]
Your class isn't an aggregate since it has user-provided constructors, but it does have a default constructor. [dcl.init]/7:
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;
[dcl.fct.def.default]/4:
A special member function is user-provided if it is user-declared and
not explicitly defaulted […] on its first declaration.
So your constructor is not user-provided, therefore the object is zero-initialized. (The constructor is not called since its trivial)
And finally, in case this was not clear, to zero-initialize an object or reference of type T means:
if T is a scalar type (3.9), the object is initialized to the value obtained by converting the integer literal 0 (zero) 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;
[…]
Thus either
Your compiler is bugged
…or your code triggers undefined behavior at some other point.
* The answer is still yes in C++11, though the quoted sections are not equivalent.
What is the default value of a function pointer in C++? (Apparently it can't be NULL, so what is it?)
How is this program supposed to behave and why?
struct S { void (*f)(); };
int main()
{
S s = S();
s.f(); // What is the value of s.f?
}
First any pointer can be null. It is the one universal truth about pointers. That said, yours will be null, but not necessarily for the reasons you may think;
C++11 § 8.5,p10
An object whose initializer is an empty set of parentheses, i.e., (), shall be value-initialized.
This is important because your declaration includes this :
S s = S();
By the definition of value initialization:
C++11 § 8.5,p7
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.
Which brings us to what it means for your object-type to be zero-initialized:
C++11 § 8.5,p5
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 (103)
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.
103) As specified in 4.10, converting an integral constant expression whose value is 0 to a pointer type results in a null pointer value.
The latter is the reason you're pointer is null. It will not be guaranteed-so by the standard given the same code, but changing the declaration of s to this:
S s;
Given a declaration like the above, a different path is taken through the standard:
C++11 § 8.5,p11
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.
Which then begs the last question, what is default initialization:
C++11 § 8.5,p6
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.
In your case the object s is zero-initialized which means the function pointer is NULL.
struct S { void (*f)(); };
int main()
{
S s = S();
if ( s.f == NULL)
std::cout << "s.f is NULL" << std::endl;
}
Output:
s.f is NULL
Online demo.
A function pointer can be NULL and you may assign NULL to it. Have a look here for instance:
#include <iostream>
using namespace std;
struct S { void (*f)(); };
int main()
{
S s = S();
s.f = NULL;
return 0;
}
I believe the way you call the constructor of the structure(with ()), f will be NULL.
Function pointer can be NULL, this way you can indicate that they don't point to anything!
In C++ (and C), pointers (regardless of type) do not have a default value per se; they take what ever happens to be in memory at the time. However, they do have a default initialised value of NULL.
Default Initialisation
When you don't explicitly define a constructor, C++ will call the default initialiser on each member variable, which will initialise pointers to 0. However, if you define a constructor, but do not set the value for a pointer, it does not have a default value. The behaviour is the same for integers, floats and doubles.
Aside
int main()
{
S s = S();
s.f(); // <-- This is calling `f`, not getting the pointer value.
}
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
What do the following phrases mean in C++: zero-, default- and value-initialization?
Today I came to know about 3 types of initialization in C++:
Zero Initialization
Default Initialization
Value Initialization
I have googled about it but I found no satisfactory results. All I get is a few standards. What I have understood until now is this: in case of value initialization, a data member can get value equal to zero in some cases.
Please elaborate them (standards) with examples. Also please don't just provide the text from the standard.
Thanks
The types of initialization refer to the language grammar. Here are two examples:
T * p1 = new T;
T * p2 = new T();
The object *p1 is default-initialized, and the object *p2 is value-initialized.
The effect of the initialization depends on the type T: 1) If T is a fundamental, then default-initialization does nothing (i.e. the object is left uninitialized), while value initialization equals zero initialization in that case and means the object is set to zero.
2) If T is an aggregate (i.e. class without constructors or destructor or assignment operator), then each element is recursively default- or value-initialized.
3) If T is of class-type and does have user-defined constructors, then both default- and value-initialization cause a call to the default constructor.
Note that member objects of classes with constructors can in turn be default- or value-initialized:
struct Foo {
int x;
int y;
Foo() : x() { }
};
Now when you say Foo a; then a is default-initialized, so the default constructor is called. This in turn causes a.x to be value-, i.e. zero-initialized, while a.y remains default-, i.e. un-initialized.
(Note that it's not really possible to value-initialize an automatic object, though in C++11, brace-initialization may be used to cause value-initialization, as in Foo a{};. (This behaves exactly the same as Foo a; in our example, consequent to the third paragraph.))
This is dealt with in 8.5 Initializers [dcl.init].
Zero Initialization
5/ 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. As specified in 4.10, converting an integral constant expression whose value is 0 to a pointer type results in a null pointer
value.
— 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 zeroinitialized 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.
Basically, it's equivalent to a memset(&obj, 0, sizeof(objt));, except that it account that the memory representation of a null pointer might not be a 0 value (even though it is represented by a 0 in the language).
// foo.cpp
static char const* p; // p is zero-initialized
// during static initialization
static void init() {
if (!p) { p = new char[500]; } // fine as p has been 0-initialized
}
Note: personally I still prefer to use = nullptr to initialize p, just to make the intent clear...
Default Initialization
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.
Or basically, a call to the default constructor, accounting for arrays, at least for classes. The last point is a caveat for built-ins (such as int). Those are simply left as is (with garbage inside).
Default initialization is what is called when you defined a variable but do not initialize it explicitly. It is also what happens to attributes of a class that are not listed in the initializer list. So the caveat for built-ins is quite important to a programmer.
int function() {
int a; // <-- a is default-initialized (which means nothing happens...)
return a; // <-- uses a, so technically undefined behavior
}
struct A { int a; A() {} }; // During the call to A::A(),
// A::a is default-initialized (nothing happens...)
The absence of explicit initialization is a left-over from C. It's normally so for optimization reasons but leads to Undefined Behavior if one attempts to use the value...
Value Initialization
7/ 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.
It is a mix of both the above, meaning that the following syntax:
template <typename T> T value() { return T(); }
^~~
provides a suitably initialized instance of T whether T is a class type or a built-in type. It's important for templated code to be able to have such a unified syntax.
Note that with C++11, it is also possible to use T{} to achieve the same effect (which helps disambiguates from functions).
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.
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
What do the following phrases mean in C++: zero-, default- and value-initialization?
I am confused about an issue in C++.
When creating an object on the stack using the default constructor, I thought either one of the following two syntax notations would give the same result:
class MyClass { public: int i; }
int main()
{
MyClass a = MyClass();
MyClass b;
}
However, the first syntax initializes the field to zero, whereas the second one leaves the field uninitialized. So my questions are:
Why is this so? I thought fields in C++ were not supposed to be automatically initialized.
Is there any other differences between the two syntaxes?
Do these syntax variations have separate names to distinguish them from each other?
I’m currently using Microsoft Visual C++ 2010 Express.
Thanks!
In the first, you copy-initialize a from a value-initialized instance of MyClass. From the C++03 standard, §8.5/7:
An object whose initializer is an empty set of parentheses, i.e., (), shall be value-initialized.
And from §8.5/5:
To value-initialize an object of type T means:
if T is a class type with a user-declared constructor, 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
To zero-initialize an object of type T means:
if T is a scalar type, 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 zero-initialized;
if T is a union type, the object’s first named data member) is zero-initialized;
if T is an array type, each element is zero-initialized;
if T is a reference type, no initialization is performed.
In the second, you declare b in a manner that would cause it to be default-initialized if MyClass were not a POD type -- §8.5/5:
To default-initialize an object of type T means:
if T is a non-POD class type, 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.
However, because MyClass is a POD type, b is uninitialized -- §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 non-static 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.
Basically, this is a (relatively) simple WTF in the language, where primitive types will not be initialized by default. The first syntax explicitly initializes them- the second doesn't. User-defined types will always be initialized, so it's only meaningful if you don't initialize it in the constructor, and it will be an error if you don't call the init functions of UDTs that need them.
UDTs that do not do anything insane should not require the first syntax and it's normal to use the second.