Home > database >  Why primitive to class type conversion destroys object values?
Why primitive to class type conversion destroys object values?

Time:12-24

Why in the below code when I set c1 = 10 destroys all other values of variables (a, b, c) of the object. The statement should call the constructor and as the constructor is defined it sets the values of a to 10, but when I try to access values of b and c; it is giving me garbage values.

#include<iostream>
using namespace std;
class abc{
    private:
    // properties
    int a,b, c;
    
    public:
    
    void setdata(int x,int y)
    {
        a = x;
        b = y;
    }
    void showdata(){
        cout << "a = " << a << " b = " << b << "\n";
    }
    
    // constructors
    abc(){}
    
    abc(int k)
    {
        a=k;
    }
};
int main()
{
    
abc c1; // object intialization
c1.setdata(6,7); // setting values of properties
c1.showdata(); // printing values

c1 = 10; // primitive to class type conversion, constructor is being called
c1.showdata(); // why value of b and other variables is getting changed ?

return 0;

}

CodePudding user response:

This is equivalent to

c1 = abc(10);

The constructor abc(int k) doesn't initialize values b and c, therefore the member variables contain some random values. These random values, from the temporary abc(10) object, are then copied to c1.


The same is true for constructor abc(), here neither member variable is initialized, so they all contain "garbage" values. You will see this, when you call showdata right after construction

abc c1;
c1.showdata();

CodePudding user response:

In fact c1 = 10; invokes 2 distinct steps:

  • a temporary abc object is constructed from the abc(int k) constructor - obviously its b and c values are not set
  • that temporary is then assigned to c1 using one of the move assignement operators which will replace all the members.

After that, the temporary is destroyed.

If you have good reasons to not overide previous values in a copy, you could provide a custom copy or move assignment operator. But beware, that will be used for every assignment.

CodePudding user response:

When you wrote:

c1 = 10;

On the right hand side, the converting constructor is used to create a temporary object of type abc.

Next, the assignment operator is used to assign that temporary object on the right hand side to the object on the left hand side.

Also, note that the converting constructor abc(int k); only assign to the data member a and leave the data members b and c as it is. But since you've not explicitly initialized member b and c they have garbage value. And using/accessing those values(b and c) leads to undefined behavior.

This is why it is advised that

always initialize built in types in local/block scope.

To solve this you can use in-class initializers as shown below:

class abc{
    private:
    // USE IN-CLASS INITIALIZERS
    int a = 0,b = 0, c =0;
    
    public:
    
    void setdata(int x,int y)
    {
        a = x;
        b = y;
    }
    void showdata(){
        cout << "a = " << a << " b = " << b << "\n";
    }
    
    // constructors
    abc(){}
    
    abc(int k)
    {
        a=k;
    }
};

Also not that instead of assigning a value to the data member a inside the constructor body, you should use constructor initializer list to initialize it as shown below:

class abc{
    private:
    // USE IN-CLASS INITIALIZERS
    int a = 0,b = 0, c =0;
    
    public:
    
    void setdata(int x,int y)
    {
        a = x;
        b = y;
    }
    void showdata(){
        cout << "a = " << a << " b = " << b << "\n";
    }
    
    // constructors
    abc(){}
    //use constructor initializer list
    abc(int k): a{k}
    {
       //no need to assign to `a` here
    }
};

CodePudding user response:

Your line

c1 = 10; 

creates a new object where only your constructor abc(int k) is called. Now you have a temporary object, which will be moved into the existing one c1. As you only overwrite your variable a, all others are not set explicitly.

I have no idea if it is intended behavior, that you create a temporary obejct which will be moved into an existing object. If you do not want it, you should make your constructor explicit.

BTW: You constructor did not initialize your variable a but overwrite it. For an int type, it doesn't matter but for other types which are not default constructible, it will not work.

You should always the constructor initializer to initialize your variables like:

abc(int k): a{k}{}
  • Related