Thanks, but can you explain why it happens? I know that it has to do with a lack of copy constructor, but I am trying to understand what exactly happens.
First, num points to dynamic ("heap") memory (new int{0}).
Then, you change num to point to automatic ("stack") memory (*a.num = 4).
Finally, your destructor tried to delete the memory that num points to, but it no longer points to dynamic memory, so you get an error. You can only delete memory use allocate with new.
Your issue is a combination of two problems, as the others pointed out. Just to be clear: Even if you didn't have the b object, you would still have the issue I just stated.
I don't know what I was thinking, kyrresc. :)
Just listen to coder777.
The point of the shallow copy on line 16 is that you copy pointer. So after that both objects a and b are seeing the the same pointer. Thus both trying to free them. The destructor of the object which is called later will try to delete an already freed memory.
are you here de-referencing the num-pointer, giving it a value 4? I was just curious as it with this syntax "looks" like a de-referencing of the a-object.
The precedence of member access (.) is higher than the precedence of dereferencing.
(Also, the associativity of the dereferencing operator is right-to-left, so something like *p++ is interpreted as *(p++) as well, where ++ and * have the same precedence).
Precedence rules are derived from the rules of the language/syntax itself. If you're ever not sure of a precedence rule, adding more parenthesis doesn't hurt unless you are gratuitous to the point where it hurts readability.
PS: Hypothetically, if the a object were a pointer that could be dereferenced,
it would have to be done like: a->num; or (*a).num;.
Thanks... I was messing up something in my head, thinking that the re-assignment no longer pointed to dynamic memory. But that's wrong because the same memory is being used, it just has a 4 in it rather than a 0 now.
I have now implemented a copy constructor and an assignment operator for my class. Do these two, i.e. the copy constructor and the assignment operator "do the same"? Just that
Constructor constructs a new object.
Assignment modifies existing object.
1 2 3 4 5 6 7 8
std::string lotr = /*the entire text of the Lord of the Rings books*/
// assert: lotr is a very long string
std::string twilight = "hello";
// assert: twilight.size() == 5
lotr = twilight; // copy assignment
// assert: lotr.size() == 5
The assignment does not just make the lotr to contain "hello". It has to get rid of a huge text first.
EDIT:
Lets repeat your original error (and some) without classes:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
int* Anum = newint {0}; // default construct A
// Lets call the dynamically allocated int object "HeapInt"
// Anum points to HeapInt
int* Bnum = Anum; // copy construct B; initialize with A
// Bnum points to HeapInt. This is shallow copy
int* Cnum = newint {0}; // default construct C
// Cnum points to "VictimOfAssign"
Cnum = Anum; // copy assignment
// nobody points to VictimOfAssign. This is memory leak
// Cnum points to HeapInt. This is shallow copy
delete Cnum; // C destructor deallocates HeapInt
delete Bnum; // B destructor; error - pointed to address is not allocated
delete Anum; // A destructor; error - pointed to address is not allocated
// VictimOfAssign still exists, but is unreachable
And then with deep copy:
1 2 3 4 5 6 7 8 9 10 11
int* Anum = newint {0};
int* Bnum = newint {*Anum}; // copy construct B; initialize with A's data
int* Cnum = newint {0};
*Cnum = *Anum; // copy assignment
delete Cnum; // C destructor deallocates the int that C points to
delete Bnum; // B destructor deallocates the int that B points to
delete Anum; // A destructor deallocates the int that A points to