[英]VS2013 default initialization vs value initialization
Consider the code below 请考虑以下代码
struct B
{
B() : member{}{};
int member[10];
};
int main()
{
B b;
}
VS2013 compiler gives the following warning: VS2013编译器发出以下警告:
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 警告C4351:新行为:数组'B :: member'的元素将默认初始化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. 使用C ++ 11,并应用“默认初始化”的概念,意味着B.member的元素将不会被初始化。
But I believe that member{}
should perform value initialization and not default initialization. 但我相信member{}
应该执行值初始化而不是默认初始化。 Is the VS2013 compiler broken? VS2013编译器坏了吗?
$8.5/6 $ 7.0 / 6
To default-initialize an object of type
T
means: — ifT
is a (possibly cv-qualified) class type (Clause 9), the default constructor forT
is called (and the initialization is ill-formed ifT
has no accessible default constructor); 默认初始化类型为T
的对象意味着: - 如果T
是(可能是cv限定的)类类型(第9节),则调用T
的默认构造函数(如果T
没有可访问的默认值,则初始化是错误的构造函数);
— ifT
is an array type, each element is default-initialized; - 如果T
是数组类型,则每个元素都是默认初始化的;
— otherwise, no initialization is performed. - 否则,不执行初始化。
If a program calls for the default initialization of an object of aconst
-qualified typeT
,T
shall be a class type with a user-provided default constructor. 如果程序要求对const
-qualified类型T
的对象进行默认初始化,则T
应为具有用户提供的默认构造函数的类类型。
$8.5.1 $ 8.5.1
List-initialization of an object or reference of type
T
is defined as follows: 列表初始化对象或类型T
引用定义如下:
— If the initializer list has no elements andT
is a class type with a default constructor, the object is value-initialized. - 如果初始化列表没有元素且T
是具有默认构造函数的类类型,则对象将进行值初始化。
— Otherwise, ifT
is an aggregate, aggregate initialization is performed (8.5.1). - 否则,如果T
是聚合,则执行聚合初始化(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). 如果列表中的initializer-clause少于聚合中的成员,则未显式初始化的每个成员都应从空的初始化列表(8.5.4)初始化。 [ Example: [ 例如:
struct S { int a; const char* b; int c; }; S ss = { 1, "asdf" };
initializes
ss.a
with1
,ss.b
with"asdf"
, andss.c
with the value of an expression of the formint()
, that is,0
. 初始化ss.a
与1
,ss.b
与"asdf"
,和ss.c
与以下形式的表达式的值int()
即,0
。 —end example ] - 末端的例子 ]
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. B::member
正在初始化值,对于int
数组,它将变为零初始化。 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: 如果在Debug模式下编译并运行,则会产生输出:
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. 第二行中的数字是0xCCCCCCCC
,VC ++编译器在调试模式下填充内存的调试模式。 Thus B::member
is being zero-initialized, while no initialization is performed for C::member
. 因此B::member
被初始化为零,而没有为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. 免责声明:我知道从未初始化的变量读取是未定义的行为,但这是我能想到的最好的证明 。
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'
}
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. C4351意味着您应该检查您的代码...如果您想要新的行为,可能是因为该数组已显式添加到构造函数的成员初始化列表中,请使用警告编译指示来禁用该警告。 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. 因此,您必须为一行添加#pragma warning (suppress:4351)
或为整个文件添加#pragma warning (suppress:4351)
#pragma warning (disable:4351)
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.