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