简体   繁体   English

VS2013默认初始化vs值初始化

[英]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: — 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); 默认初始化类型为T的对象意味着: - 如果T是(可能是cv限定的)类类型(第9节),则调用T的默认构造函数(如果T没有可访问的默认值,则初始化是错误的构造函数);
— if T 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 a const -qualified type T , 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 and T is a class type with a default constructor, the object is value-initialized. - 如果初始化列表没有元素且T是具有默认构造函数的类类型,则对象将进行值初始化。
— Otherwise, if T 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 with 1 , ss.b with "asdf" , and ss.c with the value of an expression of the form int() , that is, 0 . 初始化ss.a1ss.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'
}

The MSDN page says: MSDN页面说:

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM