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.
Related
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.
Assume I have a pointer void* p, then after some passing in and out of functions, let's say p is now pointing to int. Then do I need to manually delete as delete static_cast<int*>(p)?
In most places people say delete only happen when there is new. But in this case, it's not but does C++ itself remember to release that memory?
That all depends on how the int you're pointing to was allocated, you only delete what you new.
Correct (the int is new'd):
int* a = new int;
void* p = a;
//somewhere later...
delete static_cast<int*>(p);
Bad (the int is automatically managed):
int a = 0;
void* p = &a;
//somewhere later...
delete static_cast<int*>(p);
Answering the comment code, doing:
int* a = new int;
void* p = a;
delete p;
Is never okay. You should never delete through a void*, it's undefined behavior.
side note : in modern C++ you really shouldn't be using new or delete, stick with smart pointers or standard containers.
The short answer is: "It depends".
In most places people say delete only happen when there is new.
That's true so far as it goes. To avoid wasting resources and to ensure all destructors are called correctly every new has to be balanced by a delete somewhere. If your code can follow several paths you have to make sure that every path calls delete (if calling delete is appropriate).
The can get tricky when exceptions are thrown which is one reason why Modern C++ programmers generally avoid using new and delete. Instead they use the smart pointers std::unique_ptr and std::shared_ptr along with the helper template functions std::make_unique<T> and std::make_shared<T> (see the SO question: What is a smart pointer and when should I use one?) to implement a technique known as RAII (Resource Acquisition Is Instantiation).
But in this case, it's not …
Remember that the phrase ... when there is a new refers to the object the pointer points to not the pointer itself. Consider the following code...
int *a = new int();
void *p = a;
if (SomeTest())
{
delete a;
}
else
{
a = nullptr;
}
// This line is needed if SomeTest() returned false
// and undefined (dangerous) if SomeTest() returned true
delete static_cast<int *> (p);
Is that last line of code needed?
The object that a and p both point to was created by calling new so delete has to be called on something. If the function SomeTest() returned false then a has been set to nullptr so calling delete on it won't affect the object we created. Which means we do need that last line of code to properly delete the object that was newed up in the first line of code.
On the other hand, if the function SomeTest() returned true then we've already called delete for the object via the pointer a. In that case the last line of code is not needed and in fact may be dangerous.
The C++ standard says that calling delete on an object that has already been deleted results in "undefined behaviour" which means anything could happen. See the SO question: What happens in a double delete?
does C++ itself remember to release that memory?
Not for anything created by calling new. When you call new you are telling the compiler "I've got this, I will release that memory (by calling delete) when appropriate".
do I need to manually delete
Yes: if the object pointed to needs to be deleted here and the void * pointer is the only pointer you can use to delete the object.
This looks simple question but my friend debated with me that below program invokes UB. But I think he is incorrect.
Consider following program:
#include <iostream>
int main()
{
int* p=new int[3]();
int* q=p;
for(int i=0;i<3;i++)
std::cout<<q[i]<<' ';
delete[] q;
std::cout<<'\n';
}
Is this program's behavior well defined? What happen if I write delete[] p; instead of delete[] q; ? Is it valid?
Yes the program is well defined. First you create a pointer assigned to newly allocated memory.
int* p=new int[3]();
Then you create another pointer pointing to that memory
int* q=p;
You then use that pointer to assign data into that memory. After that you delete memory which is pointer to q which is the same as p which is okay. The program returns and all is well
delete doesn't care about what variable you use. What is important is that the memory that the pointer points to was created with new and that you only call delete once on the memory.
The pointer returned by the new[] operator is not the start of the allocated memory but rather points to the first object (or the object at index 0). Now, based on the compiler you're using, the run-time system stores the number of objects, n, somewhere where it can be retrieved if you only know the memory location pointed by p.
According to this blog, the deletion of a vector performs this operation in reverse:
When you do "delete[] p", you are saying, "p points to a bunch of
objects, but I'm not telling you how many." In this case, the compiler
needs to generate extra code to keep track of how many it needs to
destruct. This extra information is kept in a "secret place" when the
vector is allocated with "new[]".
Since doing int *q = p essentially points to the same array's 0th object, it is equivalent to call delete[] q and delete[] p.
Operator delete can be applied ONLY to memory (i.e. address) that was allocated with operator new. If you allocate once you should free (detele) also once, does not metter which pointer (variable storing address) is used, so your code is valid.
But, remember, after you delete[] q neither q nor p DO NOT have to be used. The best way is assigne NULL to both pointers.
No UB. It will work fine. Not much to add here.
If I go...
int *foo = new int;
foo += 1;
delete foo;
Most of the time it crashes. Is there a reason for this? I'm trying to have the pointer point one spot forward (4 bytes). Thanks.
Edit (six months later): This was the first question I asked on SO, and it was a silly question and deserved the downvotes. It can be deleted if it's of no use to learners. I was indeed talking about allocating an int of four bytes on the heap, then moving the pointer four bytes forward, and then deleting the int pointer, essentially deleting God knows what, leading to undefined behaviour. Thanks for your help.
The only thing you can safely pass to delete is something you got when you called new, or nullptr, in that case the delete won't do anything.
You changed the value of the pointer - therefore it isn't "something you got when you called new"
You must pass to delete the value that new returned. You don't do that.
I think that you are confused as to what you are passing to delete. I think that you believe that delete foo will delete the memory associated with the variable. It doesn't. It deletes the memory whose address is stored in foo.
As an example, this is legitimate:
int* foo = new int;
int* bar = foo;
delete bar;
What matters is not the name of the variable, but rather the value of the variable.
Here's another example:
int* arr = new int[10];
int* ptr = arr;
for (int i; i < 10; i++)
{
*ptr = i;
ptr++;
}
delete[] arr;
In order to perform pointer arithmetic, and retain the address returned by new[], we introduced an extra variable. I used an array because it doesn't make sense to perform arithmetic on a pointer to a single value.
Note that in the code above, it could be written more clearly using arr[i] = i and so avoid the need for a second pointer variable. I wrote it as above to illustrate how you might code when pointer arithmetic is the right option.
If I remove a pointer to an object, what will be removed? Only the pointer or also the object which the pointer points to?
For example:
Assume I have a class with a variable
int *root
If I do the following in a method of that class
int *current = root;
delete current;
Will root also be deleted or only the pointer current?
I think you have a misconception about what delete does: delete deletes an object pointed to by a pointer that was previously allocated with new:
int* p = new int; // Create a new int and save its address in p
delete p; // Delete the int
Note that this does not delete p itself in any way, but only the object p points to! You can still use p like a normal variable, e.g. reassign it.
When you have multiple pointers to a pointee you only need to call delete on one of them.
int* root = new int;
int* current = root;
delete current;
std::cout << *root; // undefined behavior
The behavior of delete is described in §5.3.5:
6 If the value of the operand of the delete-expression is not a null
pointer value, the delete-expression will invoke the destructor (if
any) for the object or the elements of the array being deleted. In the
case of an array, the elements will be destroyed in order of
decreasing address (that is, in reverse order of the completion of
their constructor; see 12.6.2).
Yes, root is deleted, but depending of the compiler, current can still contain the address of an unexisting variable. So you have to do this to avoid mistakes :
delete current;
current = 0;
int *pointer = new int;
After this statement pointer would be pointing( pointer would be containing the address ) to a block of memory enough to store integer. What internally happens is some chunk from free store would be assigned allocated status.
When you execute
delete pointer;
That memory is returned back to free store so as to fulfill future needs. But you pointer would be containing the same address. When you execute delete again , it would led to undefined behavior since that block is already returned to free store ( that means you have lost the control over that memory through this pointer )
So, to be on safe side you generally set pointer to 0 after deleting that memory.
pointer = NULL;
In implementation of operator delete there is code which check if pointer is NULL, if it is then it returns. So, it's said that there's no harm in deleting NULL pointer.
I hope I have covered every basics.