If I try to compile this code
struct A {
const int j;
};
A a;
I'll get an expected error:
error: uninitialized const member in ‘struct A’
but, if I try to compile this one:
struct A {
const int j;
};
A * a = new A();
I'll get a successful build.
The question is: why does new allocation allows creating a variable with const member without explicit constructor and stack allocation - doesn't ?
It's not because of the heap allocation, but because of the parenthesis you use when allocating. If you do e.g.
A* a = new A;
it would also fail.
The reason it works when you add the parenthesis is because then your structure is value initialized, and for a POD-type like A value-initialization value-initializes each member, and the default value-initialization for int is zero.
That means it would probably work creating the variable on the stack as well, if you just add the value-initialization parenthesis:
A a = A(); // watch out for the http://en.wikipedia.org/wiki/Most_vexing_parse
Though that brings other potential problems, better use uniform initialization if you can (requies C++11):
A a{};
This is ill-formed as of C++14. §12.1 [class.ctor] says that
4 A defaulted default constructor for class X is defined as deleted
if:
[...]
any non-variant non-static data member of const-qualified type (or array thereof) with no brace-or-equal-initializer does not have a
user-provided default constructor,
[...]
A default constructor is trivial if it is not user-provided and if:
its class has no virtual functions (10.3) and no virtual base classes (10.1), and
no non-static data member of its class has a brace-or-equal-initializer, and
all the direct base classes of its class have trivial default constructors, and
for all the non-static data members of its class that are of class type (or array thereof), each such class has a trivial default
constructor.
§8.5 [dcl.init] says in turn that
7 To default-initialize an object of type T means:
if T is a (possibly cv-qualified) class type (Clause 9), the default constructor (12.1) for T is called (and the initialization is
ill-formed if T has no default constructor or overload resolution
(13.3) results in an ambiguity or in a function that is deleted or
inaccessible from the context of the initialization);
[...]
8 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;
[...]
The empty pair of parentheses results in value-initialization. The default constructor for A is defined as deleted per [class.ctor]/p4. Thus, by [dcl.init]/p8, value-initialization means default-initialization, and by p7 the initialization is ill-formed because the constructor is deleted.
The C++11 version actually allowed value-initialization in this context; it says for value-initialization that, among other things,
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.
Since by the definition above the default constructor is trivial (even though it is deleted), it is not actually called. This was considered a defect in the standard and the relevant wording was changed by CWG issue 1301.
Compiler vendors usually do implement defect resolutions, so this could be considered a bug in GCC 4.8 that's been fixed in 4.9.
Related
I was wondering under which circumstances a class may have no default constructor but will still be value-initialized. The typical case for "no default ctor" is that a parametrized one is present and the default ctor is not defaulted (= default).
Quoting from the 2020 standard, chapter 9.4.1, Initializers/General (the latest draft contains equivalent wording):
To value-initialize an object of type T means:
(8.1) — if T is a (possibly cv-qualified) class type (Clause 11), then
(8.1.1) — if T has either no default constructor (11.4.5.2) or a default constructor that is user-provided or deleted, then the object is default-initialized;
And
11.4.5.2 Default constructors [class.default.ctor]:
1 A default constructor for a class X is a constructor of class X for which each parameter that is not a function parameter pack has a default argument (including the case of a constructor with no parameters). If there is no user-declared constructor for class X, a non-explicit constructor having no parameters is implicitly declared as defaulted (9.5)
I read this such that 8.1.1 does not refer to cases with no constructor at all (because, as 11.4.5.2 explains, a default constructor is then implicitly declared). Instead I understand it as "No default constructor at all" (including implicit ones).
Value-initialization happens with new()or brace-initialization, and for excess elements in arrays that are brace-initialized (as in struct T{}; T arr[1]{};).
Neither construct compiles when there is "no default constructor". Are there situations where objects of types without default constructor are value-initialized at all? Am I misreading 8.1.1?
It’s just saying that value-initializing an object of a class type that lacks a default constructor tries and fails to default-initialize it. Note that the alternative in the next bullet still default-initializes it after zero-initializing it, so it’s not default-initialized any more for not having a default constructor.
Depending on one’s interpretation of [class.default.ctor], it might also be considered to cover the case where a class can be default-initialized via a variadic constructor template:
struct A {
template<class ...TT> A(TT...);
};
auto a=A(); // value-initialization -> default-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) {}.
I don't understand how C++11 brace initialization rules work here.
Having this code:
struct Position_pod {
int x,y,z;
};
class Position {
public:
Position(int x=0, int y=0, int z=0):x(x),y(y),z(z){}
int x,y,z;
};
struct text_descriptor {
int id;
Position_pod pos;
const int &constNum;
};
struct text_descriptor td[3] = {
{0, {465,223}, 123},
{1, {465,262}, 123},
};
int main()
{
return 0;
}
Note, that the array is declared to have 3 elements, but only 2 initializers are provided.
However it compiles without error, which sounds strange, as the last array element's reference member will be uninitialized. Indeed, it has NULL value:
(gdb) p td[2].constNum
$2 = (const int &) #0x0: <error reading variable>
And now the "magic": I changed Position_pod to Position
struct text_descriptor {
int id;
Position_pod pos;
const int &constNum;
};
becomes this:
struct text_descriptor {
int id;
Position pos;
const int &constNum;
};
and now it gives the expected error:
error: uninitialized const member ‘text_descriptor::constNum'
My question: Why it compiles in the first case, when it should give an error (as in the second case).
The difference is, that Position_pod uses C - style brace initialization and Position uses C++11 - style initialization, which call Position's constructor. But how does this affect the possibility to leave a reference member uninitialized?
(Update)
Compiler:
gcc (Ubuntu 4.8.2-19ubuntu1) 4.8.2
It will be clear that
struct text_descriptor td[3] = {
{0, {465,223}, 123},
{1, {465,262}, 123},
};
is list-initialisation, and that the initialiser list is not empty.
C++11 says ([dcl.init.list]p3):
List-initialization of an object or reference of type T is defined as follows:
If the initializer list has no elements and T is a class type with a default constructor, the object is value-initialized.
Otherwise, if T is an aggregate, aggregate initialization is performed (8.5.1).
...
[dcl.init.aggr]p1:
An aggregate is an array or a class (Clause 9) with no user-provided constructors (12.1), no brace-or-equal-initializers for non-static data members (9.2), no private or protected non-static data members (Clause 11), no base classes (Clause 10), and no virtual functions (10.3).
td is an array, so it is an aggregate, so aggregate initialisation is performed.
[dcl.init.aggr]p7:
If there are fewer initializer-clauses in the list than there are members in the aggregate, then each member not explicitly initialized shall be initialized from an empty initializer list (8.5.4).
This is the case here, so td[2] is initialised from an empty initialiser list, which ([dcl.init.list]p3 again) means it is value-initialised.
Value-initialisation, in turn, means ([dcl.init]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), ...
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.
...
Your class text_descriptor is a class with no user-provided constructor, so td[2] is first zero-initialised, and then its constructor is called.
Zero-initialisation means ([dcl.init]p5):
To zero-initialize an object or reference of type T means:
if T is a scalar type (3.9), ...
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, ...
if T is an array type, ...
if T is a reference type, no initialization is performed.
This is well-defined regardless of text_descriptor's default constructor: it just zero-initialises the non-reference members and sub-members.
Then the default constructor is called, if it is non-trivial. Here's how the default constructor is defined ([special]p5):
A default constructor for a class X is a constructor of class X that can be called without an argument. If there is no user-declared constructor for class X, a constructor having no parameters is implicitly declared
as defaulted (8.4). An implicitly-declared default constructor is an inline public member of its class. A defaulted default constructor for class X is defined as deleted if:
...
any non-static data member with no brace-or-equal-initializer is of reference type,
...
A default constructor is trivial if it is not user-provided and if:
its class has no virtual functions (10.3) and no virtual base classes (10.1), and
no non-static data member of its class has a brace-or-equal-initializer, and
all the direct base classes of its class have trivial default constructors, and
for all the non-static data members of its class that are of class type (or array thereof), each such class has a trivial default constructor.
Otherwise, the default constructor is non-trivial.
So, the implicitly defined constructor is deleted, as expected, but it is also trivial, if pos is a POD type (!). Because the constructor is trivial, it is not called. Because the constructor is not called, the fact that it is deleted is not a problem.
This is a gaping hole in C++11, which has since been fixed. It happened to have been fixed to deal with inaccessible trivial default constructors, but the fixed wording also covers deleted trivial default constructors. N4140 (roughly C++14) says in [dcl.init.aggr]p7 (emphasis mine):
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;
As T.C. pointed out in the comments, another DR also changed so that td[2] is still initialised from an empty initialiser list, but that empty initialiser list now implies aggregate initialisation. That, in turn, implies each of td[2]'s members is initialised from an empty initialiser list as well ([dcl.init.aggr]p7 again), so would seem to initialise the reference member from {}.
[dcl.init.aggr]p9 then says (as remyabel had pointed out in a now-deleted answer):
If an incomplete or empty initializer-list leaves a member of reference type uninitialized, the program is ill-formed.
It is unclear to me that this applies to references initialised from the implicit {}, but compilers do interpret it as such, and there's not much else that could be meant by it.
The first version (the one with _pod suffix) still works but gives no error because for the z value, the default value of int is chosen (the 0). Idem for the const int reference.
In the second version, you cannot define a const reference without giving it a value. The compiler gives you an error because later you cannot assign any value to it.
In addition, the compiler you're using plays an important role here, maybe it's a bug, just because you are declaring a class member before an int member.
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) {}.
According to N2628 related to c++0x, non-static data member initializers can be overridden by explicitly defined constructors, but it appears to be slightly nebulous about the implicitly defined copy constructor.
In particular, I've noticed that with Apple clang version 3.0, the behavior varies depending on whether the struct (or class) is a POD.
The following program returns output "1", which indicates that the copy-constructor is ignoring the right-hand-side, and instead substituting the new non-static data member initializer (in this example, the boolean true value for X::a).
#include <iostream>
#include <string>
struct X
{
std::string string1;
bool a = true;
};
int main(int argc, char *argv[])
{
X x;
x.a = false;
X y(x);
std::cout << y.a << std::endl;
}
However, confusingly, if you comment out string1:
// std::string string1;
then the behavior works as I expected (the output is "0"), presumably because there is no implicitly generated copy-constructor, and therefore the data is copied.
Does the C++0x specification really suggest that it is a good idea to allow the implicitly defined copy-constructor to not copy the contents of the right-hand side? Isn't that less useful and unintuitive? I find the non-static member initializer functionality to be quite convenient, but if this is the correct behavior, then I will explicitly avoid the feature due to its tricky and unintuitive behavior.
Please tell me I'm wrong?
UPDATE: This bug has been fixed in the Clang source repository. See this revision.
UPDATE: This bug appears fixed in Apple clang version 3.1 (tags/Apple/clang-318.0.45) (based on LLVM 3.1svn). This version of clang was distributed as part of Xcode 4.3 for Lion.
It isn't shadowy after all, see highlighted parts of the standards excerpt:
The section on defaulted copy/move constructors (§ 12.8) is a bit too lengthy to quote in it's entirety. The low-down is that non-static member fields with initializers are still simply copied by the defaulted copy/move constructor
§ 12.8:
-6. The implicitly-defined copy/move constructor for a non-union class X performs a memberwise copy/move
of its bases and members. [ Note: brace-or-equal-initializers of non-static data members are ignored. See
also the example in 12.6.2. —end note ] The order of initialization is the same as the order of initialization
of bases and members in a user-defined constructor (see 12.6.2). Let x be either the parameter of the
constructor or, for the move constructor, an xvalue referring to the parameter. Each base or non-static data
member is copied/moved in the manner appropriate to its type:
if the member is an array, each element is direct-initialized with the corresponding subobject of x;
if a member m has rvalue reference type T&&, it is direct-initialized with static_cast(x.m);
otherwise, the base or member is direct-initialized with the corresponding base or member of x.
Virtual base class subobjects shall be initialized only once by the implicitly-defined copy/move constructor
This is the sample referred to:
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-equalinitializer will not take place. —end example ]
For completeness, the corresponding section on the defaulted default constructor:
§ 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. If that user-written default constructor would be ill-formed, the program is ill-formed.
If that user-written default constructor would satisfy the requirements of a constexpr constructor (7.1.5),
the implicitly-defined default constructor is constexpr. Before the defaulted default constructor for a
class is implicitly defined, all the non-user-provided default constructors for its base classes and its nonstatic
data members shall have been implicitly defined. [ Note: An implicitly-declared default constructor
has an exception-specification (15.4). An explicitly-defaulted definition might have an implicit exception-specification,
see 8.4. —end note ]