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

时间:2019-06-27 04:30:58

标签: c++ c++11 initialization 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();
}

这是结果:

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

要解决此问题:

  1. 如果我摆脱了默认的构造函数-问题就解决了。
  2. 如果对类的成员变量进行了括号初始化,则将其分配为0或默认值。 例如:

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

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

2 个答案:

答案 0 :(得分:8)

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

这是copy-list-initialization,因为执行了value-initialization

  

否则,如果braced-init-list为空并且T是具有默认构造函数的类类型,则执行value-initialization

value-initialization的影响,

  

1)如果T是没有默认构造函数或具有用户提供或删除的默认构造函数的类类型,则对象为default-initialized;

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

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

然后value-initialization的行为将更改为

(重点是我的)

  

2)如果T是具有既不由用户提供也未删除的默认构造函数的类类型(即它可能是具有隐式定义或默认默认构造函数的类), 对象为zero-initialized ,如果它具有非平凡的默认构造函数,则为default-initialized

请注意这里的区别,临时对象首先是zero-initialized。然后,所有具有内置类型的数据成员都将初始化为0var4仍为default-initialized)。

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

default initializer list的工作方式。

  

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

然后所有数据成员由指定的初始化程序初始化;在您的示例中,它们都是value-initialized,因为效果var4default-initialized,其他成员是zero-initialized0

答案 1 :(得分:4)

a = {};

此行并不意味着该类中的所有变量都获得一个{}初始化程序。 而是调用一个(未定义,因此自动生成的)复制(或移动)赋值运算符,该赋值运算符从使用{}创建的对象(即具有未初始化变量)进行浅复制/移动到您拥有的对象。

var4 似乎要清除,但实际上是从新对象var4中复制/移动,并且由于std :: string具有默认构造函数,因此为空。 / p>

避免此类事情的简单解决方案是在类中初始化非类变量,例如

class A
{
    int var = 0;
    ...

};