Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does brace initialization assignment fill variables with garbage?

I have fallen into the belief that variables are assigned their default values when using brace initialization. But I was wrong.

In the following example:

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

Here is the result:

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

To fix it:

  1. If I get rid of the default constructor - the problem goes away.
  2. If a class's member variable is brace-initialized, then it will be assigned 0 or the default value. E.g.:

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

Can someone please explain why this happens? What am I missing here?

like image 242
Code_So1dier Avatar asked Jun 27 '19 04:06

Code_So1dier


People also ask

What do empty brackets mean in C++?

What do empty brackets mean in struct declaration? T object {}; is syntax for value initialization (4). Without the curly brackets, the object would be default initialized. To be pedantic, this is not a "struct declaration". It is declaration of a variable.

What is brace initialization?

If a class has non-default constructors, the order in which class members appear in the brace initializer is the order in which the corresponding parameters appear in the constructor, not the order in which the members are declared (as with class_a in the previous example).

Does default constructor initialize c++?

Implicitly defined (by the compiler) default constructor of a class does not initialize members of built-in types. However, you have to keep in mind that in some cases the initialization of a instance of the class can be performed by other means. Not by default constructor, nor by constructor at all.

How do you initialize a struct variable in C++?

// In C++ We can Initialize the Variables with Declaration in Structure. Structure members can be initialized using curly braces '{}'. For example, following is a valid initialization.


2 Answers

a = {};

This line does not mean that all the variables inside the class get an {} initializer. It instead calls a (not defined, so automatically generated) copy (or move) assignment operator which does a shallow copy/move from an object created with {} (i.e. with uninitialized variables) to the object you have.

var4 seems to be cleared, but it's actually copied/moved from the new object var4, and since std::string has a default constructor, it's empty.

The simple solution to avoid stuff like that is to initialize your non-class variables inside the class, say

class A
{
    int var = 0;
    ...

};
like image 29
Michael Chourdakis Avatar answered Oct 16 '22 14:10

Michael Chourdakis


a = {}; is an assignment, a is assigned from a temporary object constructed from {}. The implicitly-generated assignment will perform member-wise assignment on all the data members, then the point would be how the temporary object is initialized from {}.

This is copy-list-initialization, as the effect, value-initialization is performed.

Otherwise, If the braced-init-list is empty and T is a class type with a default constructor, value-initialization is performed.

As the effect of value-initialization,

1) if T is a class type with no default constructor or with a user-provided or deleted default constructor, the object is default-initialized;

A has a user-provided default constructor, and as the effect of default initialization, that default constructor is used to initialize the temporary object. The user-provided default constructor's body is empty, then for the temporary object, var4 will default-initialized by std::string's default constructor, all the other data members with build-in type will have indeterminate values.

  1. If I get rid of default constructor - the problem goes away.

Then the behavior of value-initialization will change to

(emphasis mine)

2) if T is a class type with a default constructor that is neither user-provided nor deleted (that is, it may be a class with an implicitly-defined or defaulted default constructor), the object is zero-initialized and then it is default-initialized if it has a non-trivial default constructor;

Note the difference here, the temporary object will be zero-initialized at first. Then all the data members with build-in type are initialized to 0 (var4 is still default-initialized).

  1. If class's member variable is brace-initialized, then it will be assigned to 0 or default value.

This is how default initializer list works.

Through a default member initializer, which is simply a brace or equals initializer included in the member declaration, which is used if the member is omitted in the member initializer list

Then all the data members are initialized by the specified initializer; in your sample they're all value-initialized, as the effect, var4 is default-initialized, other members are zero-initialized to 0.

like image 90
songyuanyao Avatar answered Oct 16 '22 14:10

songyuanyao