当前位置: 首页 > 知识库问答 >
问题:

VS2013默认初始化与值初始化

黄成荫
2023-03-14

考虑以下代码

struct B
{
    B() : member{}{};
    int member[10];
};

int main()
{
    B b;
}

VS2013编译器发出以下警告:

警告C4351:新行为:数组“B::member”的元素将默认初始化1

这里有记载

使用C 11,并应用“默认初始化”的概念,意味着B. part的元素将不会被初始化。

但我认为,成员{}应该执行值初始化,而不是默认初始化。VS2013编译器是否损坏?

8.5美元/6

默认初始化类型为T的对象意味着:-如果T是(可能是cv限定的)类类型(第9条),则调用T的默认构造函数(如果T没有可访问的默认构造函数,则初始化是病态的)
-如果T是数组类型,则每个元素默认初始化
-否则,不执行初始化<如果程序调用常量限定类型的对象的默认初始化,T应为具有用户提供的默认构造函数的类类型。

$8.5.1

类型为T的对象或引用的列表初始化定义如下:
-如果初始值设定项列表没有元素,并且T是具有默认构造函数的类类型,则对象为值初始化对象
-否则,如果T是聚合,则执行聚合初始化(8.5.1)。

如果列表中的初始值设定项子句少于聚合中的成员,则未显式初始化的每个成员应从空初始值设定项列表中初始化(8.5.4)。[示例:

  struct S { int a; const char* b; int c; };
  S ss = { 1, "asdf" };

初始化ss。a带有1的ss。b带有“asdf”和ss。c,表达式的值的形式为int(),即0-结束示例]


共有3个答案

卞浩漫
2023-03-14

MSDN页面说:

C4351意味着您应该检查您的代码...如果您想要新行为,这很可能是因为数组已显式添加到构造函数的成员初始化列表中,请使用警告杂注来禁用警告。对于大多数用户来说,新行为应该没问题。

因此,您必须为一行添加#pragma警告(禁止:4351)或为整个文件添加#pragma警告(禁用:4351)

卫建义
2023-03-14

编译器警告不正确;它实际上是按照标准要求执行值初始化。

例子:

#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'
}
裴理
2023-03-14

这似乎是一条措辞错误的警告消息(我很惊讶它首先会打印一条警告),但行为是正确的<正在初始化成员的值,对于int的数组,该值将变为零初始化。这可以使用以下内容进行演示:

#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;
}

如果您在调试模式下编译并运行,则会输出:

0 0 0 0 0 0 0 0 0 0
-858993460 -858993460 -858993460 -858993460 -858993460 -858993460 -858993460 -858993460 -858993460 -858993460

第二行中的数字是0xCCCCCCCC,这是VC编译器在调试模式下填充内存的调试模式。因此B::成员是零初始化的,而C::成员不执行初始化。

免责声明:我知道读取未初始化的变量是未定义的行为,但这是我能想到的最好的证明。

 类似资料:
  • 根据我的参考,基元类型具有默认值,对象为null。我测试了一段代码。 行将是指向变量的错误,表示,而在给定引用中,将作为默认值。但是,使用下面给定的代码,它将实际打印。 第一个代码可能会出什么问题?类变量的行为是否与局部变量不同?

  • 问题内容: 众所周知,根据JLS7 p.4.12.5, 每个实例变量均使用默认值初始化。例如(1): 但是我一直认为,这样的类实现(2): 绝对等于示例(1)。我期望,复杂的Java编译器会看到(2)中的所有这些初始化值都是多余的,并忽略了它们。 但是突然对于这两个类,我们有两个不同的字节码。 例如(1): 例如(2): 问题是: 为什么?但这是显而易见的要优化的事情。什么原因? UPD: 我使用

  • 我在Visual Studio2019中有一个Xamarin表单解决方案。我现在只使用Android版本。完整的错误是: 在此进程中,java.lang.IllegalStateException Message=Default FirebaseApp未初始化AppCardView.Sample.android。确保首先调用FirebaseApp.InitializeApp(上下文)。 在我的An

  • null 必需的 获取java对象(根元素),它完全表示xml和每个由默认值初始化的成员。 当我试图在不显式设置值的情况下marshall xml时,默认值并不能使sence...有什么方法可以在不自定义生成的类的情况下,用默认值填充xml吗? .xsd的示例: 和java类:

  • 问题内容: 如果未将显式值传递给方法,我想用一些默认值初始化方法的参数-像这样: 我得到了错误: 我该如何解决? 问题答案: 这里常见的习惯用法是将默认值设置为一些哨兵值用于此目的,这是典型值,然后您可以检查该值。 您可能还会看到用于哨兵的实例。 后一个版本的优点是可以传递给函数,但有一些缺点(请参见下面@larsmans的评论)。如果您不认为需要将有意义的参数传递给您的方法,那么我建议您使用它。

  • 问题内容: 我知道当我初始化一个char数组时: 要么 为什么不喜欢 初始化数组: 为什么它们不同?它是Java哲学的本质之一还是其​​背后的某些原因? 问题答案: 如果您曾经使用过 C ,那么答案就非常简单。在 C语言中 ,创建数组的方式是在堆栈上分配一个足以容纳元素数量的静态内存长度,并使用指针指向第一个元素-或堆上动态内存长度,然后用指针指向第一个元素。 在 C ++中 ,第二个版本已更改为