我已经陷入了这样的信念,即使用Brace初始化时会为变量分配其默认值。但是我错了。
在以下示例中:
#include <string>
#include <iostream>
#include <stdint.h>
class A
{
public:
A() {}
~A(){}
int var1;
int32_t var2;
int64_t var3;
std::string var4;
double var5;
float var6;
std::string info() const {
return "var1=" + std::to_string(var1) + " " +
"var2=" + std::to_string(var2) + " " +
"var3=" + std::to_string(var3) + " " +
"var4=" + var4 + " " +
"var5=" + std::to_string(var5) + " " +
"var6=" + std::to_string(var6) + " " +
"n"
;
}
};
int main()
{
A a;
std::cout << "Before assigning variables: " << a.info();
a.var1 = 1;
a.var2 = 2;
a.var3 = 3;
a.var4 = "4";
a.var5 = 5;
a.var6 = 6;
std::cout << "After assigning variables: " << a.info();
a = {};
std::cout << "After brace init assignment: " << a.info();
}
这是结果:
Before assigning variables: var1=0 var2=0 var3=4198240 var4= var5=0.000000 var6=0.000000
After assigning variables: var1=1 var2=2 var3=3 var4=4 var5=5.000000 var6=6.000000
After brace init assignment: var1=2114725200 var2=32766 var3=4199416 var4= var5=0.000000 var6=0.000000
修复它:
- 如果我摆脱了默认的构造函数 - 问题消失了。
如果一个类的成员变量是支撑限制的,则将分配0或默认值。例如:
class A { public: A() {} ~A(){} int var1{}; int32_t var2{}; int64_t var3{}; std::string var4{}; double var5{}; float var6{}; };
有人可以解释为什么会发生这种情况吗?我在这里缺少什么?
a = {};
是一个分配,a
是从{}
构造的临时对象分配的。隐式生成的分配将对所有数据成员执行成员的分配,那么关键是如何从{}
初始化临时对象。
这是副本列表限制,因为效果,进行了价值定位。
否则,如果支撑式列表为空,而T是具有默认构造函数的类类型,则进行Value-Initialization。
作为价值定性的影响,
1(如果t是没有默认构造函数的类类型或用户提供或删除的默认构造函数,则该对象是默认的initialized;
A
具有用户提供的默认构造函数,并且作为默认初始化的效果,该默认构造函数用于初始化临时对象。用户提供的默认构造器的主体为空的,对于临时对象,var4
将通过std::string
的默认构造函数默认initialial,所有其他具有Build-In类型类型的数据成员都将具有不确定的值。
- 如果我摆脱了默认构造函数 - 问题消失了。
然后,价值定位的行为将变为
(强调我的(
2(如果t是具有默认构造函数的类类型,该类型既不提供用户提供也不删除(也就是说,它可能是具有隐式定义或默认默认型构建器的类对象为零initialized ,然后如果它具有非平凡的默认构造函数,则将其默认限制化;
请注意,此处的差异,临时对象首先将被零定位。然后,所有具有建筑类型的数据成员都将初始化为0
(var4
仍被默认initialized(。
- 如果类的成员变量是支撑式化的,则将其分配给0或默认值。
这是默认初始化器列表的工作方式。
通过默认成员初始化器,这仅是成员声明中包含的支撑或等于初始化器,如果在成员初始化器列表中省略了会员
中使用该成员。
然后所有数据成员都是由指定的初始化器初始化的;在您的示例中,它们都是价值限制的,因为效果var4
被默认为initialized,其他成员对0
进行了零命名。
a = {};
此行并不意味着类内的所有变量都获得{} initializer。相反,它调用(未定义,因此自动生成(副本(或移动(分配操作员,该操作员从用{}(即具有非注重变量(创建的对象进行浅复制/移动到您拥有的对象。
var4 似乎要清除,但实际上是从新对象var4复制/移动的,并且由于std :: string具有默认的构造函数,因此是空的。<<<<<<<<<<<<<<<<
避免类似内容的简单解决方案是初始化班级中的非类变量,例如
class A
{
int var = 0;
...
};