Reputation: 2668
Suppose I have the dynamic memory allocation through p1
as follows,
int* p1 = new int;
*p1 = 1;
I know that the memory referenced by p1
can be freed by using
delete p1;
p1 = nullptr;
But I wonder if there is another pointer p2
pointing at 1
, can I delete
this pointer in order to free the memory? And what would happen to pointer p1
? In addition, what is the relationship between p1
and p2
essentially? For example,
int* p1 = new int;
*p1 = 1;
int* p2 = p1;
// Can I delete p2 like this? And what would happen to p1?
delete p2;
p2 = nullptr;
Upvotes: 3
Views: 386
Reputation: 3911
when allocating dynamic memory using new it should be freed by delete, as long as you create p1 using new then free it using delete.
you declare p2 as a pointer pointing at the same memory p1 points to then if you want to free memory call delete on p1
not p2
to be readable however that memory can be freed by calling delete on p1 or p2.
if you call delete on p1 then make p2 to point to null in order not to dereference it by mistake because writing:
delete p1;
*p2 = 1;
will cause an undefined behavior.
Upvotes: 0
Reputation: 10557
You can delete either p1
or p2
. There will be no difference. But you should not delete both. Plus once you deleted one you should not use the other. Programmer is responsible for this. The language itself will not provide any help. There are tons of different ways to write bad code here.
There are several techniques/patterns for handling this. Very often smart pointers are used for this. Look at std::shared_ptr documentation. Do not use outdated auto_ptr
.
My favorite pattern is "ownership". This means that one pointer "owns" the allocation while all others just use. This requires certain discipline while programming but once this effort is applied, the resulting code is clear and simple. For example:
class MyClass
{
public: ~MyClass() { for(char *p: myStringsDict) delete p; }
private:
std::unordered_set<char*> myStringsDict;
};
Looking at this class it is clear (although it would be nice to add a proper comment) that it owns a dictionary of strings and these strings are valid as long as the instance of this class exists. These pointers can be used in structures that are owned by this class, they can be passed as parameters to functions, etc. It is clear when they should not be used any more.
In server programming when multiple threads are running, double deleting can be very dangerous and difficult to track down. Because after deleting the first pointer the memory becomes free and may be allocated for some other purpose on a different thread. When the second pointer is being freed it may happen that it is deleting a valid allocation while other piece of code has no idea about this and is continuing to use this piece of memory.
Really good solution for all these problems is garbage collection. When explicit allocations are used, programmer needs to apply additional effort in this or that way.
Upvotes: 2
Reputation: 119847
Let's explore the real estate analogy, where memory plays the role of land and pointers are, not-so-surprisingly, act as addresses.
A pointer variable is a yellow post-it note. You can write a street address on it. A variable allocated from the free store is a patch of land at some address.
int *p = new int;
You ask the city to find a small unused patch of land somewhere and assign the title to yourself. You write down its street address on a yellow note.
*p = 1;
You build a neat little house at that address.
int *q = p;
You make a copy of the yellow note. You forget about it for some time.
delete p;
You demolish the building and give up your rights to the patch of land. The city may allocate it to somebody else. Perhaps someone wants to build another small building there, or maybe lay down railway tracks or set up a shark pool. Note this does nothing whatsoever to any of your yellow notes.
p = nullptr;
You wipe a yellow note clean. Your other yellow note lingers on.
*q = 2;
You find the other yellow note, read a streat address off it and assume that land is yours. Bad move. You proceed to build a neat little house on someone else's land. The new owners couldn't care less (they have no way of knowing). Tomorrow they may demolish your building and put their own in place, or overrun you with a train, or perhaps dump 100000 tons of water and 3 makos on you. That's rather unpleasant! Don't touch what's not yours.
Upvotes: 1
Reputation: 26476
you're describing a very known problem in (old) C++ : when several pointers point to the same dynamic memory, which one deletes it?
if you delete both p1
and p2
you double delete the memory, which have undefined behavior (a crash, in the best case), if you delete p1
or p2
and you keep using the memory via the other pointer - you are using dangling pointer, which is undefined behavior (a crash, in the best case).
you need to make sure that when one pointer is deleted - you are not to use that memory in other pointers.
C++11 introduced a standard way of dealing this problem: using a self counting pointer, which only the last pointer deletes the memory:
auto p1 = std::make_shared<int>(0);
auto p2 = p1;
now, the last pointer alive will delete the allocated memory, and you don't have to worry at all who's deleting what.
Upvotes: 4
Reputation: 1
And what would happen to pointer p1? In addition, what is the relationship between p1 and p2 essentially?
Their essential relationship is that they are pointing to the same address obtained from dynamic memory allocation after the assignment int* p2 = p1;
.
So deleting either of them will free the allocated memory. Setting one of them to nullptr
won't affect the other though.
So you're left with a dangling pointer that cannot be deleted safely.
Upvotes: 2
Reputation: 4493
You can delete p2
, but dereferencing p1
will result in undefined behavior, and possible segmentation fault.
It works like this:
p1
and p2
pointing to this memory location.p2
deleted - p1
is still pointing to this memory location.
There is no leak, and everything is alright - just don't dereference p1
. You can freely do p1 = nullptr
, but can't *p1 = 1
. Also, you cannot delete p1
, since it's deleted already, and you'll probably catch segfault.Upvotes: 8