Below code was working fine. However, when I enable p=&b
in GetValue
, the code failed \"Debug Assertion Failed\". Why?
class A{
int
Firstly, it is important that you only delete
memory that was allocated using new
. Currently, your class A
stores a pointer p
that isn't allocated using new
, but you do delete p
as if it had been. The result of this is undefined behavior, which means that your program is not guaranteed behave correctly, and very weird bugs should be expected.
Secondly, in the function A::GetValue(int b);
, the parameter b
is a temporary variable. When GetValue
is called, some space is made on the call stack to pass b
's value, where it resides for the lifetime of the function. But after GetValue
returns, b
no longer exists there. While C++ allows you to store pointers to invalidated memory, you need to be careful to avoid using such a pointer.
To make your class A
work correctly takes a fair bit of touching up, but I'll try to explain as I go. While currently it doesn't seem to make much sense to store an int*
pointer where a simple int
member would do, I'll keep using the pointer to help your understanding, and let the managing of a raw pointer be a learning exercise.
Most of the problems stem from A::GetValue(int)
. Here, you're storing the address of a temporary variable, and in a context where a new
-ed pointer is expected. You should instead make sure to correctly allocate memory, and not store a pointer to the transient parameter b
:
A::GetValue(int b){
if (p == nullptr){
// if p is null, it needs to be allocated before being written to
p = new int(b); // initialize the memory at p to have value b
} else {
// otherwise, p has already been allocated, and its old value can be overwritten
*p = b;
}
}
Another more subtle problem arises when you write the following code:
A a1, a2;
a1.GetValue(13);
a2 = a1;
What will happen after these lines is that the p
member of a1
will be deleted twice, causing yet more undefined behavior. The culprit is the automatically generated copy assignment operator, which simply copies p
from a1
to a2
by value. To fix it, you need to write your own copy assignment operator and copy constructor as follows. The copy constructor is a little complex because there are lots of different cases to be handled.
class A {
...
A(const A& other) : p(nullptr) {
if (other.p){
p = new int(*other.p); // allocate new int and initialize with other's value
}
}
A& operator=(const A& other){
if (p){
// if this is managing a pointer
if (other.p){
// if other is managing a pointer too, just copy value
*p = *other.p;
} else {
// otherwise, since other is null, delete and make this null
delete p;
p = nullptr;
}
} else {
// if this is not managing a pointer
if (other.p){
// other is managing a pointer, time to allocate
p = new int(*other.p);
}
// nothing needs to be done if both are null
}
}
The importance of doing this is explained in the Rule of Three.