Consider the following class with a user-defined default ctor.
class TestClass {
public:
TestClass()
:data_(999) {
}
double getData() const {
return data_;
}
private:
double data_;
};
Then we create objects:
TestClass *p2 = new TestClass();
TestClass *p1 = new TestClass;
Any difference for using the 2 statements above in any condition?
Thank you,
Short answer: No difference.
Longer answer: §5.3.4,15 states that
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.
And §8.5,16 says
If the initializer is (), the object is value-initialized.
Now what is value-initialization and default-initialization, is defined by §8.5,5-7:
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), [...]
— 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.
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 [...]
— if T is an array type, each element is default-initialized;
— otherwise, no initialization is performed.
[...]
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 [...]
— 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.
(emphasis mine)
Together, since your class has a user provided default constructor, value initialization and default initialization is the same, so both new expressions give the same behavior, namely the default constructor is called.
It is a different thing with e.g. ints:
int *p2 = new int(); // value-initialized, i.e. zero-initialized, *p2 is 0
int *p1 = new int; // default-initialized, i.e. no initialization. *p1 is some garbage. Or whatever.
Related
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) {}.
Why does
struct wrapper
{
explicit wrapper(void *);
wrapper() = default;
int v;
};
int main() { return wrapper().v; } // You should run this in Debug mode
return 0xCCCCCCCC, whereas
struct wrapper { wrapper() = default; int v; };
int main() { return wrapper().v; }
and
struct wrapper { int v; };
int main() { return wrapper().v; }
both return 0?
During value-initialization, if T is a class type without a user-provided or deleted default-constructor, then the object is zero-initialized (§8.5/8.2). This is indeed the case with wrapper.
Your first example matches the third case for zero-initialization (§8.5/6.1, emphasis mine)
— 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 sub-object 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
So in your first example, v should be zero-initialized. This looks like a bug.
In your second and third example you no longer have a user-provided constructor, but you do have a default-constructor that isn't user-provided or deleted so your example still falls into the third case for zero-initialization, which is to zero-initialize each non-static data member. VS is correct there.
This does appear to be a bug in MSVC. In all three cases wrapper has no user-provided default constructor, so initialization with wrapper() invokes:
(All citations from n3690)
(8.5/11) An object whose initializer is an empty set of parentheses, i.e., (), shall be value-initialized.
(thanks to dyp), this will result in zero-intialization of int v
Initialization then refers us to the rule:
(8.5/8) 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.
The zero initialization rules state:
(8.5/6) 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
int v being a data member of wrapper is zero initialiazed itself according to:
(8.5/6) 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
Which is not the behavior you observe.
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) {}.
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?
If I have a class for example:
class Info
{
int x;
int y;
};
which I used to created an object,
Info *p = new Info();
Does the brackets beside Info mean i'm value initializing it? How does it different from this, Info *p = new Info; ?
I know there is a question which differentiate between different meanings in new and old C++ language but I want to know the semantic difference between default and value initialization e.g. Does value initialization means initializing something to zero?
A declared variable can be Zero Initialized, Value Initialized or Default Initialized.
In your example:
Info *p = new Info(); <------- Value Initialization
Info *p = new Info; <------- Default Initialization
The C++03 Standard 8.5/5 aptly defines each:
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 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.
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
The C++ standard says (8.5/5):
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.
With this code
struct Int { int i; };
int main()
{
Int a;
}
the object a is default-initialized, but clearly a.i is not necessarily equal to 0 . Doesn't that contradict the standard, as Int is POD and is not an array ?
Edit Changed from class to struct so that Int is a POD.
From 8.5.9 of the 2003 standard:
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.
The class you show is a POD, so the highlighted part applies, and your object will not be initialized at all (so section 8.5/5, which you quote, does not apply at all).
Edit: As per your comment, here the quote from section 8.5/5 of the final working draft of the current standard (I don't have the real standard, but the FDIS is supposedly very close):
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.
Your variable is not initialized.
Use
Int a = Int();
to initialize your POD or declare a standard constructor to make it non POD;
But you can also use your POD uninitialized for performance reasons like:
Int a;
a.i = 5;
No, the object a is not default-initialized. If you want to default-initialize it, you have to say:
Int a = Int() ;