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.
Related
lets think we have a code like this :
int * ptr = new int;
int *nptr = ptr
int * ptr2 = new int;
int *nptr2 = 2*nptr+ptr2;
delete ptr;
delete ptr2;
ptr = NULL;
ptr2 = NULL;
So now the nptr and nptr2 is dangling pointer .I know that we can overload new allocating function to trace leaked memory (if we dont use delete command in code ) but dont know how to trace or monitor dangling pointers .
dangling pointers that points to leakded memory?
A pointer that has leaked, by definition is not being pointed by anything. A dangling pointer by definition points to memory that hasn't been leaked. This is a contradiction.
int *nptr2 = 2*nptr+ptr2;
This is ill-formed. Pointers cannot be multiplied by integers, and pointers cannot be added to pointers (I'm assuming the assumption is that result of the ill-formed multiplication is also a pointer). Furthermore, if this pointer arithmetic produced anything other than nptr, nptr+1, nptr2, nptr2+1, then the result would technically be undefined.
but dont know how to trace or monitor dangling pointers .
It's perfectly fine and normal to have dangling pointers. What isn't fine is indirecting through dangling pointers or relying on their value. At least for indirection, you can use an address sanitiser to try catch such bugs. It can find some uses of dangling pointers particularly those to dynamic memory such as the pointers in the question. It's not as good at detecting dangling pointers to automatic variables. On the other hand, compiler can catch simple cases such as returning pointer to local variable.
Alternatively, you can modify your program to use std::shared_ptr so that as long as you still hold a shared pointer, it cannot become dangling. This comes at a small cost of overhead, but it makes it much easier to reason about lifetime correctness.
First of all "dangling pointers that points to leakded memory" makes no sense. I suppose you mistakenly use "leaked memory" for objects that are already destroyed. In your code there is no memory leak. You have a memory leak when you do not have a pointer to some dynamically allocated obejct anymore, as in:
{
int* x = new int;
} // x goes out of scope, no way to delete the int
Further, it is not clear what this line is supposed to do int *nptr2 = 2*nptr+ptr2;. It is not valid C++, hence I am going to ignore it for the rest of the answer. Also the last two lines are not that relevant (maybe for code that comes after the shwon code but not here).
So we are left with:
int * ptr = new int;
int *nptr = ptr
int * ptr2 = new int;
delete ptr;
delete ptr2;
You create two int via new. You delete two int. No memory is leaked. After delete ptr the pointer nptr points to a no longer existing object. nptr is said to be a dangling pointer.
With that out of the way, we can turn to your actual question: How to monitor dangling raw pointers?
You cannot. A raw pointer is rather primitive. It stores an address. And thats all. The pointer is not aware whether there is an object at that adress or not. This is one reason you should not use new and delete and raw pointers to manage memory. Use smart pointers. For example if you share ownership between two std::shared_ptr then the pointee will be kept alive as long as one of the shared pointers is alive. A shared pointer cannot dangle (unless you do something wrong).
I would recommend that you not use raw pointers. If you use smart pointers that then you will never(*) have a dangling pointer. The whole purpose of smart pointers is to ensure that the lifetime of both the pointer and what is pointed to is managed together.
Use std::unique_ptr, std::shared_ptr (and std::weak_ptr if needed).
You can use tools like Valgrind and AddressSanitizer to ensure that you do not use dangling pointers.
(*) never is perhaps too strong, at least make it more difficult.
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.
This question already has answers here:
C++ deleting a pointer when there are 2 pointers pointing to the same memory locations
(4 answers)
Closed 3 years ago.
Class example
{
};
int main()
{
Example* pointer1 = new example();
Example* pointer2;
pointer2 = pointer1;
delete pointer1;
}
Should I delete pointer2? I think it's in the stack and I don't need to delete.
Short answer: No.
pointer1 and pointer2 are both pointers which exist on the stack. new Example allocates on the heap a new object of type Example, and its memory address is stored in pointer1. When you do delete pointer1, you are freeing the memory allocated on the heap. Since both pointer1 and pointer2 are both referencing the same memory location at the point of the delete call, it does not need to also be deleted, in fact, this would be Undefined Behaviour, and could cause heap corruption or simply your program to crash.
At the end of this, both pointer1 and pointer2 are still pointing to the same block of memory, neither are actually nullptr.
Deleting a pointer is telling the operating system that the memory at the location of that pointer is not needed anymore by the program. Remember that a pointer is just an integer that points to place in your RAM. By doing pointer2 = pointer1, you're only copying the integer and you're not moving any memory around. Therefore, by deleting the first pointer, because the second pointer points to the same location, you don't need to delete it.
I tried to deallocate same pointer twice and it failed, but if I follow the same steps with not making it NULL the code runs fine.
#include <iostream>
struct MyClass {
MyClass() {std::cout << "Allocated and Constructed" << std::endl ;}
};
int main () {
// allocates and constructs five objects:
MyClass * p1 = new MyClass[5];
delete[] p1;
delete[] p1; // The code will succeed if I comment this line of code
p1=NULL;
delete[] p1;
delete[] p1;
return 0;
}
I see a good answer to the question What happens when you deallocate a pointer twice or more in C++? but what makes it run if I make it NULL, shouldn't be the same behaviour to follow for both the cases?
You need to deallocate only what you allocate. You allocate five instances of MyClass with new[]. So that's what you need to deallocate.
You're not deallocating any pointers. Pointers don't need to be deallocated unless you dynamically allocated them, and your code doesn't dynamically allocate any pointers.
When you make the pointer nullptr (or NULL), it doesn't point to anything. So calling delete on it has no effect. The C++ standard chose to make calling delete (or delete[]) on a null pointer do nothing.
delete[] p1; doesn't ususally change the actual value of p1. (Although the C++ standard states that it can set p1 to nullptr on doing this, no compiler I've worked with actually does this).
So the behaviour on a second call to delete[] p1; is undefined since your program no longer owns that memory.
Some programmers consider it good practice to set p1 = nullptr explicitly after a delete[] since then a subsequent delete is benign. But doing that can hide other memory management issues your program has (why would your program attempt to delete the same block of memory more than once?), so I'd advise against it.
From the standard, 5.3.5$2 Delete [expr.delete] (bold by me)
In the first alternative (delete object), the value of the operand of
delete may be a null pointer value, a pointer to a non-array object
created by a previous new-expression, or a pointer to a subobject
(1.8) representing a base class of such an object (Clause 10). If not,
the behavior is undefined. In the second alternative (delete array),
the value of the operand of delete may be a null pointer value or a
pointer value that resulted from a previous array
new-expression.81 If not, the behavior is undefined.
It explains why delete a pointer twice is UB, and delete a null pointer is well defined.
I know this is pretty common question, but still new for me!
I don't understand concept of dangling pointer, was googling around, and writing test methods to find one.
I just wonder is this a dangling pointer? As whatever example I found was returning something, here I'm trying something similar!
Thanks!
void foo(const std::string name)
{
// will it be Dangling pointer?!, with comments/Answer
// it could be if in new_foo, I store name into Global.
// Why?! And what is safe then?
new_foo(name.c_str());
}
void new_foo(const char* name)
{
// print name or do something with name...
}
A dangling pointer is a pointer that points to invalid data or to data which is not valid anymore, for example:
Class *object = new Class();
Class *object2 = object;
delete object;
object = nullptr;
// now object2 points to something which is not valid anymore
This can occur even in stack allocated objects:
Object *method() {
Object object;
return &object;
}
Object *object2 = method();
// object2 points to an object which has been removed from stack after exiting the function
The pointer returned by c_str may become invalid if the string is modified afterwards or destroyed. In your example you don't seem to modify it, but since it's not clear what you are going to do with const char *name it's impossible to know it your code is inherently safe or not.
For example, if you store the pointer somewhere and then the corresponding string is destroyed, the pointer becomes invalid. If you use const char *name just in the scope of new_foo (for example, for printing purposes) then the pointer will remain valid.
A dangling pointer is a (non-NULL) pointer which points to unallocated (already freed) memory area.
The above example should be correct given that the string is not modified through new_foo.
Taken from here. Although, even if this is for C, it is the same for C++.
Dangling Pointer
When a pointer is pointing at the memory address of a variable but after some time that variable is deleted from that memory location while the pointer is still pointing to it, then such a pointer is known as a dangling pointer and this problem is known as the dangling pointer problem.
Initially
Later
Example
#include<stdio.h>
int *call();
int main() {
int *ptr;
ptr = call();
fflush(stdin);
printf("%d", *ptr);
return 0;
}
int * call() {
int x=25;
++x;
return &x;
}
Its output will be garbage because the variable x is a local variable. Its scope and lifetime are within the function call hence after returning the address of x variable x becomes dead and the pointer is still pointing to that location.
As a matter of style, I explain a dangling pointer as "a pointer which still exists, even though the object it pointed to no longer exists".
In your case, the pointer name exists for a shorter period that the object that it points to. So it's never dangling.
Inside common C++ classes, pointers dangle for a very short period, inside destructors. That's because the delete statement is before the last } of the destructor, while the pointer itself ceases to exist at the last }. If you don't want to worry about this, use e.g. unique_ptr<T>. The T* pointer will dangle for a very short time inside the unique_ptr::~unique_ptr destructor, which is perfectly safe.
Dangling pointers is a situation where you have valid pointers in the stack, but it is pointing to invalid memory. You might end up in this situation when you deallocate the heap memory before the pointers in stack deallocated.
This is a security issue. Because when you deallocate a memory, we are informing Operating System, that we no longer need this section of memory. So OS will mark that piece of memory as ready to allocate and allocate to other applications when they request for memory.
Usually, in C++, memory allocated and deallocated through a general pattern. Constructor in a class gets invoked when a class initialised and this is the right place to allocate memory in heap.Destructor will be invoked when the class instance goes out of scope, and this is the right place to deallocate memory from heap. Assume we already created a class that does allocation and deallocation of memory in constructor and destructor respectively.
int main() {
SomeClass pointer1 = SomeClass();
SomeClass pointer2 = pointer1;
}
In the above example code, there are two variables declared but both holding the same value. When the constructor invoked, it allocates a heap memory. Then we are declaring one more variable and assigning the same value. In C++ usually, when you assign a value of complex type, it does a shallow copy (unless you explicitly implemented copy constructor) instead of deep copy. That means the only pointer gets copied in Stack, but not the heap memory. Actually it is not recommended to copy heap memory for performance reasons. Now the final memory layout looks like that we have two pointers pointing to the same heap memory.
Now when the function is done with execution, local variables goes out of scope and it invokes destructor. First, pointer2 invokes destructor that deallocates the heap memory. At this point, pointer1 becomes dangling pointer. It points to a memory that is already deallocated.
From this example, we understood that the primary cause of dangling pointer is having multiple owners for the same resource. Because when one pointer deallocates memory other pointers became dangling pointers.
//Declaring two pointer variables to int
int * ptr1;
int * ptr2;
// Allocating dynamic memory in the heap
ptr1 = new int;
ptr2 = ptr1; // Having both pointers to point same dynamic memory location
//deleting the dynamic memory location
delete ptr1;
ptr1 = nullptr;
//ptr2 is still pointing the already deleted memory location
//We call ptr2 is a dangling pointer
Dangling Pointer and dangling pointer problem
If any pointer is pointing the memory address of any variable but after some variable has deleted from that memory location while pointer is still pointing such memory location.
That pointer is called as dangling pointer and the problem that arises at that time is called as dangling pointer problem.
Here are some examples: Dangling Pointer and dangling pointer problem