Reputation: 1187
I got a class named Test with a const int
member named a
:
class Test {
public:
const int a;
};
Then I instantiate a object of Test named test:
Test test;
and got an reasonable compile error "error: uninitialized const member in ‘class Test’", but something strange happened when I do like this:
Test test = Test();
There is no compile error,what happened? Won't Test()
invoke default constructor like Test test;
does and then invoke the default copy constructor? The compiler I'm using is "gcc (Ubuntu 4.8.4-2ubuntu1~14.04.3) 4.8.4" and the compiler is configured for c++11 mode.
Upvotes: 0
Views: 132
Reputation: 320381
The first initialization
Test test;
has always been ill-formed. Plainly speaking, you are not allowed to leave const objects uninitialized.
The second initialization
Test test = Test();
is well-formed in C++98, C++03 and possibly in C++11 (but see my P.S. below). Yet it is ill-formed in C++14 and later.
The relevant change is contained in the definition of value-initialization, performed in response to ()
initializer. In C++03 (and before) absence of user-defined default constructor caused value-initialization to ignore constructors entirely and work as a constructor-independent initialization mechanism. The Test()
expression would produce a properly zero-initialized temporary object.
However, in C++14 a deleted default constructor is treated by value-initialization the same way as a user-defined one: value-initialization now has to use it and, obviously, fail, since it is deleted.
C++11 8.5 (n3242)
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.
...
C++14 8.5 (n3690)
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;
— 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;
...
(Emphasis mine). Note the addition of the "or deleted" wording in the latter version, which transferred classes with deleted implicit default constructors from the second bullet point to the first one.
For this reason compilers reject the latter initialization code in C++14 mode (and accept it in C++98/C++03 modes).
In other words, the second initialization compiled in your case because your compiler apparently is configured for C++03 mode (or before).
P.S. It is quite possible (or even very likely) that my draft version of C++11 is outdated. I don't have the final version of C++11. It is likely that the final version of C++11 included the same wording as C++14. That would explain the behavior of those compilers that reject it in C++11 mode as well. In that case the separation line passes between C++03 and C++11.
Upvotes: 3
Reputation: 302748
Test test = Test();
There is no compile error,what happened?
Your compiler has a bug. The code is ill-formed. The default constructor of Test
is implicitly deleted because it would be ill-formed - you can't default-initialize a const int
. It was fixed in gcc 4.9 (I can't find a bug report for this).
You have to provide an initializer for the const
member, whether via something like Test{4}
or via a mem-initializer-list.
... then invoke the default copy constructor?
Technically, it would invoke the default move constructor, though that would be elided anyway.
Upvotes: 1
Reputation: 65
Just tried visual studio gives error to both mentioned things. Just need to use member initializer list as below
class Test {
public:
const int a;
Test():a (0)
{
}
};
int main()
{
Test test;
Test test2 = Test();
return 0;
}
Upvotes: 0