Delete dynamically allocated memory after swapping its pointer - c++

I'm relatively new to C++ and I want to understand memory management and pointers at the same time.
Let's say I have the code below
int* p1;
int* p2;
int* p3 = new int[some size];
p1 = p3;
std::swap(p1,p2);
How do I properly delete the dynamically allocated memory? Is doing delete[] p3 enough? Should I delete p2 too after that?

There is some fuzzyness in colloquial speech when you do something like this:
delete x;
We say "we delete x". Strictly speaking thats wrong, because what is deleted is the object pointed to by x.
Every object allocated via new/new[] must be destroyed via one call to delete/delete[]. Whether you have two or more pointers to the same object does not change that.
int* p1 = nullptr;
int* p2 = nullptr;
int* p3 = new int[some size]; // p3 points to the array
p1 = p3; // p1 points to the same array
std::swap(p1,p2); // now p1 == nullptr, p2 points to the array
Note that the pointers are uninitialized in your example. Reading their values causes undefined behavior. As this isnt the crux of the question I avoided that by initializing them.
There is one array created via new [] and it is that one array that you have to delete via delete []. You may not delete it twice. So either call delete[] p3; or delete[] p2;, but not both.
PS: Comments already mentioned smart pointers and I also suggest you to read about them. Nowadays you should not use raw owning pointers. An owning pointer is one that you need to call delete on, it "owns" the pointed to object. Raw pointers should only be used to "observe", ie you should never need to worry about calling delete (or delete[]) on a raw pointer. Of course you still need to take care whether the pointed to object is still alive, but that is not specific to dynamic allocation:
int* p;
{
int x = 42;
p = &x; // p points to x;
} // x goes out of scope
// here p is not a valid pointer anymore

To understand what is happening here, it would help to add some debug statements, i.e:
std::cout << p1 << " " << p2 << " " << p3 << "\n";
The trace will result in an output like:
0 0 0x15e7eb0
0x15e7eb0 0 0x15e7eb0
0 0x15e7eb0 0x15e7eb0
(Note that I initialized p1 and p1 to nullptr)
p3 initially points to some memory. After the assignment p1 = p3, p1 now points to the same memory address as p3. When you swap the pointers, now it's p2 that points to the same memory address as p3.
There are a couple of things to note here:
You must pair delete[] with the corresponding new[] (do not call delete with new[] and so forth)
Calling delete on an already deleted object is undefined behavior
Calling delete on a null pointer is perfectly safe
As you can see, dealing with raw pointers and memory allocation can easily lead to pitfalls. It's generally recommended to use smart pointers, or if you have a non-owning pointer, to use abstractions like observer_ptr to clearly indicate the pointer's purpose in the code.

Related

How memory is deallocated in shared_ptr via the operator=?

I am a beginner to c++, I was learning the concept of shared_ptr.
I also understood that
Several shared_ptr objects may own the same object and the object is destroyed and its memory deallocated when either of the following happens:
1.the last remaining shared_ptr owning the object is destroyed;
2.the last remaining shared_ptr owning the object is assigned another pointer via operator= or reset().
But when I tried to execute a sample program
class Rectangle {
int length;
int breadth;
public:
Rectangle(int l, int b)
{
length = l;
breadth = b;
}
int area()
{
return length * breadth;
}
};
int main()
{
shared_ptr<Rectangle> P1(new Rectangle(10, 5));
cout << P1->area() << endl;
shared_ptr<Rectangle> P2;
P2 = P1; //how is this possible
// This'll print 50
cout << P2->area() << endl;
// This'll now not give an error,
cout << P1->area() << endl;
cout << P1.use_count() << endl;
return 0;
}
After "P2=P1" the memory allocated to P1 has to be deallocated right?
But still we can print P1->area().
Please explain how this is happening?
2.the last remaining shared_ptr owning the object is assigned another pointer via operator= or reset().
Yes.
After "P2=P1" the memory allocated to P1 has to be deallocated right?
No. It could happen to P2 if it pointed to something. Not P1.
The logic behind the rule (2) is that the assignment overwrites the value of the first operand, so the first operand will no longer point to what it used to. If it was the last pointer to something, then nothing will point to that anymore, and it can be deleted.
What you learned about destruction of shared pointers is correct. But here, you are not destroying P1. Instead, you are assigning P1 to P2. The implementation of shared_ptr has an overloaded copy assignment operator allowing for this operation and making it correct.
Through that overloaded implementation, P2 is now a shared pointer pointing to the same object as P1 - both pointers access the same object, so you are printing the same areas. Both of them exist in a valid state and as you see, the count of pointers that manage that Rectangle object is 2.
Defining the overloaded = is aligned with the concept of shared_ptr - there are multiple pointers pointing to (owing) the same object. If you want to see a contrasting implementation, look up the unique_ptr - this is a smart pointer that assumes only one pointer has an ownership of the object. It also has an overloaded assignment operator, but using it would invalidate P1 (to my knowledge it would set it to nullptr so it would still be in a valid state, just not pointing to anything). P2 would be the only owner of the Rectangle. Worth trying, for better understanding.
You can find more on the shared_ptr functionality here.

Basic dynamic memory allocation and delete triggers an asssertion failed

I am doing some reviewing of the basics of C++, and I have some troubles understanding why my code is triggering an assertion failed.
void fonctionPointeur(int a)
{
int* p = new int;
p = &a;
std::cout << p << "----" << *p << std::endl;
delete p;
}
int main()
{
std::cout << "Hello World!" << std::endl;
int a = 6;
fonctionPointeur(a);
}
The assertion failed that I'm triggering is always different, which leads me to think that the delete of p is accessing some unknown memory slot.
When I remove the delete p; or the p = &a; then everything work just fine.
It seems to me that I'm not supposed to delete p and that it will be delete at the end of the scope, but it's dynamic allocation it's not supposed to be the case...
What am I missing here ?
In this expression
int* p = new int;
you are assigning to p a memory block allocated by new.
In this expression
p = &a;
you are assigning to p the address of mere temporary, a copy of the original variable a (as you pass it by copy in fonctionPointeur), that temporary cannot be deleted.
This is to be specific, even if you passed it by reference (void fonctionPointeur(int &a)) the problem remains, you also can't delete it as wasn't dynamically allocated.
Moreover, because p is now pointing to a, you lost access to the memory previously allocated, you cannot delete it anymore, this is a memory leak.
It seems to me that I'm not supposed to delete p
This is either correct or not correct depending on which value you are referring to:
int* p = new int;
This is the first value that you give for p. You must delete the result of new int or else the memory leaks.
p = &a;
Here, you assign a new value for p, overwriting the old value. You must not delete the result of &a because it is a pointer to an object with automatic storage. If you do delete this, then behaviour of the program is undefined.
You must have deleted p before overwriting the value because the previous value will be lost. Otherwise since this is the only copy of the pointer, this overwriting of the value guarantees a memory leak.
and that it will be delete at the end of the scope,
a which p points to will be destroyed automatically and its automatic storage will be deallocated.
The dynamic object which p used to point to will not be destroyed automatically and its dynamic storage will not be deallocated.
P.S. It his hardly ever useful to dynamically allocate an int. I recommend avoiding unnecessary dynamic allocation.
P.P.S I recommend avoiding owning bare pointers.

Regarding dynamic memory allocation in C++

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;
You can delete p2, but dereferencing p1 will result in undefined behavior, and possible segmentation fault.
It works like this:
Memory is allocated at some address.
Both p1 and p2 pointing to this memory location.
Once 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.
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.
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.
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.
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.
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.

Assign value to deleted object

I have a small homework problem.
The following code is given:
int * p;
p = new int;
*p = 5;
The question is: Why is it useless to do
p = 0;
delete p;
but usefull to do
delete p;
p = 0;
?
In my opinion, both is useless. If an object is deleted, no new value can be assigned.
I also get in both cases a Segmentation fault.
For Why it is useful for the following:
delete p;
p = 0;
Quoting from stroustrup's answer: Why doesn't delete zero out its operand?
Consider
delete p;
// ...
delete p;
If the ... part doesn't touch p then the second "delete p;" is a serious error that a C++ implementation cannot effectively protect itself against (without unusual precautions). Since deleting a zero pointer is harmless by definition, a simple solution would be for "delete p;" to do a "p=0;" after it has done whatever else is required.However, C++ doesn't guarantee that.
One reason is that the operand of delete need not be an lvalue. Consider:
delete p+1;
delete f(x);
Here, the implementation of delete does not have a pointer to which it can assign zero. These examples may be rare, but they do imply that it is not possible to guarantee that any pointer to a deleted object is 0.'' A simpler way of bypassing thatrule'' is to have two pointers to an object:
T* p = new T;
T* q = p;
delete p;
delete q; // ouch!
C++ explicitly allows an implementation of delete to zero out an lvalue operand, and I had hoped that implementations would do that, but that idea doesn't seem to have become popular with implementers.
If you consider zeroing out pointers important, consider using a destroy function:
template<class T> inline void destroy(T*& p) { delete p; p = 0; }
Consider this yet-another reason to minimize explicit use of new and delete by relying on standard library containers, handles, etc.
Note that passing the pointer as a reference (to allow the pointer to be zero'd out) has the added benefit of preventing destroy() from being called for an rvalue:
int* f();
int* p;
// ...
destroy(f()); // error: trying to pass an rvalue by non-const reference
destroy(p+1); // error: trying to pass an rvalue by non-const reference
Recall that deleting 0 is allowed. Therefore, when you do this
p = 0;
delete p; // Deleting zero is ignored
you throw away the old value of p (thus creating a memory leak), and then call delete 0, which is ignored.
When you do this, however
delete p;
p = 0;
you use the old value first (to de-allocate the int), and only then zero it out. This makes sense, because the old value of p becomes both useless and dangerous as soon as delete is executed.
This sets the pointer to null and then calls delete:
p = 0;
delete p;
It is like saying
delete 0;
I think what you are thinking is that it is setting the int that p points to to zero, but that would be done like this:
*p = 0;
p = NULL;
and
p = 0;
In the above case you are assigning value to the pointer and not to the object it points to.
Are one and the same. delete function is used to free the memory allocated dynamically to an object.
When you say
delete p;
p = 0;
It is like saying free the memory allocated to the pointer p and
then you are saying assign the pointer to NULL. Which is right.
In the other case when you do this
p = 0;
delete p;
You are saying assign the pointer to NULL first. Now the pointer p
is not pointing to any valid dynamically assigned memory. So later
when you say delete p the compiler cannot find any memory to free
and hence throws a segmentation fault.
In the first case, you are assigning the value of the POINTER p to be '0', not the value of the int that p points to. That's why it is both useless (will in fact cause a memory leak), and causes a seg fault when you try to delete from memory address '0'. EDIT - actually I just learned that the segfault is not caused by the 'delete 0', which is ignored according to the standard, so something else is causing that.
In the second case you are freeing the memory / object pointed to by p (which should be fine), and then assigning the pointer to have a value '0', which should also be Ok, so not sure why you are seg faulting there? In terms of usefulness, it used to be considered good practice to set free'd pointers to a null or '0' value so you can test for that before de-referencing them.

c++ 2 pointers to same object

I'm wondering if I have 2 pointers pointing same object, and then I delete it using pointer 1, will it still be in memory and pointer 2 will point null, or object will stay in memory and I need to use delete pointer 2 to free it?
I mean:
int *p1, *p2;
p1=new int;
p2=p1;
*p1=5;
p2=p1;
delete p1;
int x=*p2;
//Error or x=5?
The object will be gone.
Pointer 2 will not be a null pointer, but a dangling pointer, with its previous but now-invalid value; doing anything with it will be an error.1
That's exactly true for pointer 1, too. There will be no difference between the two.
1 - Well, UB, not an "error" per se. But don't do it.
It's generally good not to have two pointers pointing to the same memory. That's because if you delete one, the other will be a dangling pointer.
Anything you do with the memory after deleting it is undefined behavior.
In your case ( I assume you forgot to do p2=p1, as your question suggests ), int x=*p2; is undefined, since the memory p2 points to was deleted.