问题
Consider the code below
struct B
{
B() : member{}{};
int member[10];
};
int main()
{
B b;
}
VS2013 compiler gives the following warning:
warning C4351: new behavior: elements of array 'B::member' will be default initialized 1> test.vcxproj -> C:\Users\asaxena2\documents\visual studio 2013\Projects\test\Debug\test.exe
This is documented here
With C++11, and applying the concept of 'default initialization', means that elements of B.member will not be initialized.
But I believe that member{} should perform value initialization and not default initialization. Is the VS2013 compiler broken?
$8.5/6
To default-initialize an object of type
Tmeans: — ifTis a (possibly cv-qualified) class type (Clause 9), the default constructor forTis called (and the initialization is ill-formed ifThas no accessible default constructor);
— ifTis 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 aconst-qualified typeT,Tshall be a class type with a user-provided default constructor.
$8.5.1
List-initialization of an object or reference of type
Tis defined as follows:
— If the initializer list has no elements andTis a class type with a default constructor, the object is value-initialized.
— Otherwise, ifTis an aggregate, aggregate initialization is performed (8.5.1).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). [ Example:
struct S { int a; const char* b; int c; }; S ss = { 1, "asdf" };initializes
ss.awith1,ss.bwith"asdf", andss.cwith the value of an expression of the formint(), that is,0. —end example ]
回答1:
It seems to be an incorrectly worded warning message (and I'm surprised it is printing a warning in the first place), but the behavior is correct. B::member is being value initialized, which for an array of int turns into zero initialization. This can be demonstrated using the following:
#include <iostream>
struct B
{
B() : member{}{};
int member[10];
};
struct C
{
C() {};
int member[10];
};
int main()
{
B b;
for(auto const& a : b.member) std::cout << a << ' ';
std::cout << std::endl;
C c;
for(auto const& a : c.member) std::cout << a << ' ';
std::cout << std::endl;
}
If you compile and run in Debug mode this results in the output:
0 0 0 0 0 0 0 0 0 0
-858993460 -858993460 -858993460 -858993460 -858993460 -858993460 -858993460 -858993460 -858993460 -858993460
The numbers in the second line are 0xCCCCCCCC, the debug pattern the VC++ compiler fills memory with in Debug mode. Thus B::member is being zero-initialized, while no initialization is performed for C::member.
Disclaimer: I know that reading from an uninitialized variable is undefined behavior, but this is the best proof I could come up with.
回答2:
The compiler warning is incorrect; it is actually performing value-initialization as required by the standard.
Example:
#include <iostream>
struct B {
B() : member{}{};
int member[10];
};
int main() {
int a[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
B &b = *new (a) B;
std::cout << b.member[9]; // prints '0'
}
回答3:
The MSDN page says:
C4351 means that you should inspect your code... If you want the new behavior, which is likely, because the array was explicitly added to the constructor's member initialization list, use the warning pragma to disable the warning. The new behavior should be fine for most users.
So you have to add #pragma warning (suppress:4351) for one line or #pragma warning (disable:4351) for the whole file.
来源:https://stackoverflow.com/questions/24122006/vs2013-default-initialization-vs-value-initialization