初始化新对象时C++默认构造函数和 POD 问题



我理解默认构造函数和用户提供的空构造函数之间的区别(至少我相信我理解)以及 POD 的含义。但是,在对象初始化过程中,我不太了解一些行为:

#include <iostream>
using namespace std;
//POD
struct A {
int a, b, c;
};
//Not POD
struct B {
B() {};
int a, b, c;
};
int main(){
A a = {1,2,3} \ Case 1. Works, this is how we initialize a POD type
B b1 = {1,2,3} \ Case 2. Doesn't work, since B is not POD
B b2;          \ Case 3. Works, call the user provided empty constructor but a, b and c are not initialized
A c{};        \ Case 4. Works, initialize everything to 0
A d;          \ Case 5. Doesn't work. This is the case I don't understand
cout << a.a << a.b << a.c << endl;
cout << b1.a << b1.b << b1.c << endl;
cout << b2.a << b2.b << b2.c << endl;
cout << c.a << c.b << c.c << endl;
cout << d.a << d.b << d.c << endl;
}

如上所述,案例5是我不理解的行为。我期待它会调用默认构造函数并将每个成员初始化为 0。但是,我收到编译错误:

错误 C4700 使用未初始化的局部变量"d">

谁能帮我理解为什么它会报告上述错误?我在Windows上运行并使用Visual Studio编译器。

回答问题的另一个方面,即">PODness"。

POD 是一个遗留定义,它不再真正使用,因为它不可能涵盖各种情况。它在 C++20 中已弃用。相反,使用各种术语来讨论类与 C 结构的兼容性(因为最终,这就是它的全部内容)。

特别是,最重要的属性(至少在我看来)是:

标准布局
  • :这很重要,因为,通俗地说,当类是标准布局时,对象可以被视为一个字节序列,发送到其他程序(可能用不同的语言编写),并在接收端从这个序列重建(在考虑填充之后)。当实体序列化数据通过网络发送或保存到文件时,这起着重要作用
  • 简单可复制
  • :这很重要,因为当类是简单可复制的时,只需内存从一个对象复制字节即可从一个对象创建一个对象。这在优化中起着很大的作用
  • 平凡类型,上面平凡
  • 可复制要求的扩展:这很重要,因为当类是平凡类型时,任何随机字节序列都可以被视为该类型的有效对象(在考虑内存别名之后)。
Error C4700 uninitialized local variable 'd' used

谁能帮我理解为什么它会报告上述错误?

该错误意味着您(可能?)读取了一个不确定的值。读取不确定值的行为是未定义的(忽略某些明显不适用于您的情况的异常)。

编译器似乎已确定您在初始化之前使用了 (成员)d的值,并尝试通过诊断问题来提供帮助。

从技术上讲,读取不确定的值不会使程序格式错误,因此不允许阻止编译。您可能已将编译器配置为故意违反标准,在出现警告时拒绝编译。如果没有,那么这可能是编译器中的一致性错误。

解决方案:不要读取不确定的值。您可以将初始化值设置为初始化为零,也可以列出其他值的初始化。请参阅示例案例 1 和 4。


关于命名法的小更正:

案例 3.工作,调用用户提供的空构造函数,但 a、b 和 c 初始化为随机垃圾值

更准确地说:成员未初始化,并且可能剩下 1个不确定的值。

1在您的示例中,您使用静态存储声明变量。这些在动态初始化之前最初为零初始化。因此,在您的示例中,成员没有不确定的值,而是零。

案例 4.工作,通过调用默认构造函数将所有内容初始化为 0

int没有"默认构造函数"。它们是值初始化的。int的值初始化为零初始化。

最新更新