大括号初始化分配为什么用垃圾填充变量?

Cod*_*ier 7 c++ initialization c++11 list-initialization

我已经相信使用括号初始化时会为变量分配其默认值。但是我错了。

在以下示例中:

#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();
}
Run Code Online (Sandbox Code Playgroud)

结果如下:

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
Run Code Online (Sandbox Code Playgroud)

要解决这个问题:

  1. 如果我摆脱了默认的构造函数-问题就解决了。
  2. 如果一个类的成员变量被花括号初始化,那么它将被赋值为0或默认值。例如:

    class A
    {
    public:
        A() {}
        ~A(){}
    
        int var1{};
        int32_t var2{};
        int64_t var3{};
        std::string var4{};
        double var5{};
        float var6{};
    };
    
    Run Code Online (Sandbox Code Playgroud)

有人可以解释为什么会这样吗?我在这里想念什么?

son*_*yao 8

a = {};是分配,a是从构造的临时对象分配的{}。隐式生成的赋值将对所有数据成员执行按成员的赋值,然后重点是如何从初始化临时对象{}

这是复制列表初始化,实际上是执行了值初始化

否则,如果braced-init-list为空且T是具有默认构造函数的类类型,则将执行值初始化

作为价值初始化的影响

1)如果T是没有默认构造函数或具有用户提供或删除的默认构造函数的类类型,则该对象将被默认初始化

A具有用户提供的默认构造函数,并且作为默认初始化的结果,该默认构造函数用于初始化临时对象。用户提供的默认构造函数的主体为空,然后对于临时对象,var4将由的默认构造函数进行默认初始化std::string,所有其他具有内置类型的数据成员将具有不确定的值。

  1. 如果我摆脱了默认构造函数-问题就解决了。

然后,值初始化的行为将变为

(强调我的)

2)如果T是具有默认构造函数的类类型,该构造函数既不是用户提供也不是未删除的(也就是说,它可能是带有隐式定义或默认默认构造函数的类),则将该对象初始化为零,然后将其如果具有非平凡的默认构造函数,默认初始化

注意这里的区别,临时对象将首先被零初始化。然后,所有具有内置类型的数据成员都将初始化为0var4仍为默认初始化)。

  1. 如果类的成员变量被花括号初始化,那么它将被分配为0或默认值。

这是默认初始化程序列表的工作方式。

通过默认成员初始化程序,该成员初始化程序只是成员声明中包含的花括号或等于初始值设定项,如果成员初始化程序列表中省略了该成员,则使用该默认值

然后,所有数据成员都由指定的初始化程序初始化;在您的示例中,它们都是值初始化的,因为效果var4默认初始化的,其他成员都被零初始化0