Home > other >  User-defined object containing pointer breaks when stored in array
User-defined object containing pointer breaks when stored in array

Time:11-28

When I store a plain int in A and perform a simple get function:

#include <iostream>
class A
{
    int p;
public:
    void setint(int p_x);
    int getint();
};

void A::setint(int p_x) {p = p_x;} // set p (type int)

int A::getint() {return p;} // get p (type int)

int main()
{
    A arr_a[5];
    arr_a[0].getint();
}

it compiles and exits with code 0. However when I change int to int* and try to do the same:

#include <iostream>
class A
{
    int* p;
public:
    void setint(int p_x);
    int getint();
};

void A::setint(int p_x) {*p = p_x;} // set int pointed to by p (type int)

int A::getint() {return *p;} // get int pointed to by p (type int)

int main()
{
    A arr_a[5];
    arr_a[0].getint();
}

it compiles fine but exits with code 3221225477. Why is this so and is there still a way I can store pointers in A and store A in arrays?

CodePudding user response:

Your program has a serious flaw. Both of your given code snippets (case 1 and case 2 in your question) have undefined behavior. Lets see how it is

Case I: Code Snippet 1

In your code snippet 1, since the data member p is a built in type and you've not initialized it, so p has a garbage value and using(accessing) this value can lead to undefined behavior which is exactly what is happening in your case.

When you wrote:

 A arr_a[5];//this creates a 1D array of size 5 having elements of type `A` but the elements are default initialized 
 arr_a[0].getint();//this result in undefined behavior

The above statement creates a 1D array of size 5 having elements of type A. The problem is that since you have not initialized this array, its elements are default initialized which means that the value of data member p is also default initialized. But since you didn't use in-class initializers for variable p, p has garbage value and this leads to undefined behavior.

You can confirm this by looking at the output here.

Solution to Case I

You can solve this by initializing the data member p using in-class initializer as shown below:

#include <iostream>
class A
{
    int p = 0;//USE IN-CLASS INITIALIZER
public:
    void setint(int p_x);
    int getint();
};

void A::setint(int p_x) {p = p_x;} // set p (type int)

int A::getint() {return p;} // get p (type int)

int main()
{
    A arr_a[5];
    std::cout<<arr_a[0].getint();//now ok because we have initilaized p
}

Case II: Code Snippet 2

In this case the only difference is that now the data member p is a pointer to int that is int*. Similar to last case the pointer variable has a garbage value which can lead to undefined behavior if you try to use it as you did inside your main function by writing:

A arr_a[5];//create a 1D array of objects `A` but the elements(A objects) are default initialized  
arr_a[0].getint();//this result in undefined behavior

Solution to Case II

You can solve this by initializing the data member p using in-class initializer as shown below:

#include <iostream>
class A
{
    int* p = nullptr;//USE IN-CLASS INITIALIZER
public:
    void setint(int p_x);
    int getint();
};

void A::setint(int p_x) {*p = p_x;} // set int pointed to by p (type int)

int A::getint() {return *p;} // get int pointed to by p (type int)

int main()
{
    A arr_a[5];
    arr_a[0].getint();//now ok because we have initilaized p 
}

Summary

Both of the code snippets that you gave have undefined behavior. You can solve both of them by using in-class initilaizers to initialize data member p to a default value.

CodePudding user response:

In your 2nd case A arr_a[5] just create a array that contains 5 A. but for every A, the pointer is an undefined number (maybe 0x0), so *p is a undefined behavior. You should add A::A() and A::~A() to manage your pointer in your class just like this:

#include <iostream>
class A
{
    int *p;

public:
    A();
    ~A();
    void setint(int p_x);
    int getint();
};

A::A() : p(new int) {}
A::~A() { delete p; }

void A::setint(int p_x) { *p = p_x; } // set int pointed to by p (type int)

int A::getint() { return *p; } // get int pointed to by p (type int)

int main()
{
    A arr_a[5];
    arr_a[0].getint();
}
  • Related