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.
To make a long story short, your code has undefined behaviour, so everything can happen. The undefined behaviour starts here:
void A::GetValue(int b){
*p=b;
//p=&b; this will cause destructor to hang, why?
}
p
is nullptr
when the function is called, so *p
is undefined behaviour. The rest of your code doesn't even matter. And that's the end of the story.
Sorry to be so blunt, but your use of pointers is so completely and utterly wrong that we cannot even know for sure what the intended behaviour of the code really is. Don't use pointers if you don't need to. Don't use dynamically allocated memory if you don't need to. If you need to, use std::vector
, std::string
, std::unique_ptr
or other standard classes which hide the pointers from you, so that you don't have to write your own destructors. Avoid direct use of new
and delete
.