Sign in to follow this  

Delete a pointer passed to a function?

This topic is 3039 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

If you pass a pointer to a function in Cpp, should it be deleted explicitly at the end of the function, or will it go out of scope and be deleted by it-self freeing the memory? Example:
void myFunction(MyObjectType *anObject)
{
...
// do some stuff
...

// now delete the pointer?
delete anObject;
}

Thanks

Share this post


Link to post
Share on other sites
When things go out of scope, their destructors are called.

Destructors for primitive types do nothing. Pointers are primitive types. Thus, the pointed-at thing will not have 'delete' called on it.

This is a good thing, because many pointers should never have 'delete' called on them. You only call 'delete' to deallocate things that were allocated with 'new', and only once per allocation. Remember, 'delete' cleans up the pointed-at thing, not the pointer. The pointer requires no cleanup itself.

Share this post


Link to post
Share on other sites
And if you want a function to delete an incoming pointer you should do it this way to allow the function not only to delete the object but also modify the variable that you provided as function parameter to carry information about this deletion to the outside of the function:


void myFunction(MyObjectType *anObject)
{
...
// do some stuff
...

// now delete the pointer?
delete anObject;
}

void myOtherFunction()
{
MyObjectType *mo = new MyObjectType();
myFunction(mo);

// <- here mo still looks like a valid pointer because it still points to the address but the instance is already deleted
}


So this is how to write functions that should also modify the address variables (pointers) you hand in to the functions:



void myFunction(MyObjectType **anObject)
{
...
// do some stuff
...

// now delete the pointer?
delete (*anObject);
(*anObject) = NULL;
}

void myOtherFunction()
{
MyObjectType *mo = new MyObjectType();
myFunction(&mo);

// <- here mo is NULL and you know it is no longer pointing to a valid object
}

Share this post


Link to post
Share on other sites
Ok thank you very much. So what I understand is that I have to be careful when deleting pointers. As Waterwalker said if I delete an incoming pointer into a function inside the function I may not be able to use the object if it was instantiated outside of the function since it would be gone because I called delete on it. Also thanks to Zahlman for describing that pointers are primitives, I didn't know that.

The only thing I could comment is Waterwalker's code at the very end:

delete (*anObject);
(*anObject) = NULL;

There is no need to do the second line since like Zahlman said the pointer will be gone once it goes out of scope. Although the two lines show how to get rid of pointers to pointers, if need be. But I am not sure if it's right. I though to delete a pointer to a pointer you have to do something like this:

delete (*anObject);
delete anObject;

Since first you delete the object it-self by the first line and then you delete the middle object (pointer) by the second line. And the pointer to the pointer will be gone by it self once it goes out of scope. Or do I just need to do ONLY the second line to delete the object AND the middle pointer?

Thanks again.

Share this post


Link to post
Share on other sites
Quote:
Original post by Flopid
Since first you delete the object it-self by the first line and then you delete the middle object (pointer) by the second line. And the pointer to the pointer will be gone by it self once it goes out of scope. Or do I just need to do ONLY the second line to delete the object AND the middle pointer?


No, the pointer itself is a local variable so it makes no sense to call delete on it - it is automatically destroyed when its scope exits. The object that is pointed to is dynamically allocated on the heap, so that needs to be deleted.


void f(int *i)
{
delete i; // this deletes the object pointed to by i
}

void g()
{
int *x=new int(23); // x is a local variable, but is pointing to dynamically allocated memory
f(x);

// at this point the memory pointed to by x has been deleted

// scope exits, so the local variable x is destroyed
}


Either way, it would be a very bad design to have a function delete memory that was passed to it. If someone were to do, for example:


void h()
{
int z;
g(&z);

int y=z+10;
}


then you are into undefined behaviour and anything could happen. The compiler cannot catch this.

Are you just trying to understand how pointers and dynamic allocation works, or is there something specific you are trying to do? We very rarely call delete explicitly in modern C++.

Share this post


Link to post
Share on other sites
Quote:
Original post by Flopid
There is no need to do the second line since like Zahlman said the pointer will be gone once it goes out of scope.

Yes there is nedd. The pointer does only store a memory address to the object you have allocated with new. So you can call delete on the address stored in the pointer. This delete cleans up the memory but the pointer does still point to the address in memory. And if you access it after deleting the object stored there all kind of weird thigs start to happen with crashes being the best possible outcome that straight away tells you that you have failed [grin]

And since the pointer was in this particular example handed in to the function as parameter it does not loose scope at the end of the function.

Share this post


Link to post
Share on other sites
Quote:
Original post by Waterwalker
Quote:
Original post by Flopid
There is no need to do the second line since like Zahlman said the pointer will be gone once it goes out of scope.

Yes there is nedd. The pointer does only store a memory address to the object you have allocated with new. So you can call delete on the address stored in the pointer. This delete cleans up the memory but the pointer does still point to the address in memory. And if you access it after deleting the object stored there all kind of weird thigs start to happen with crashes being the best possible outcome that straight away tells you that you have failed [grin]


The point is, if you are organizing your code properly, it is impossible to access the invalid pointer, because there is no longer a variable in scope which corresponds to that pointer.

It is generally held that the only sane way to keep track of this memory management stuff is to have everyone clean up their own mess. Thus, functions clean up memory they allocate; they don't clean up allocated memory that was handed to them. Instead, whoever handed over the memory cleans it up afterward.

And by the way, you might want to look up this thing called "passing by reference". In modern C++, we use references where we can and pointers where we have to.

Share this post


Link to post
Share on other sites
Theres also the option of using smart poitners (such as boost::shared_ptr) which take care of cleaning themselves up. Strongly recommend learning normal pointers first though.

someone has mentioned passning a poitner to a pointer and thats a good idea but does make your function code rather confusing later on with dereferances everywhere. You could pass a pointer by reference instead, its doing the same thing but a little neater code wise


int *test = new int;
*test = 5;
Func(test);
// test should be NULL now

void Func(int *&in)
{
cout << *in;
delete in;
in = NULL;
}


Share this post


Link to post
Share on other sites
Quote:
Original post by Aardvajk

Are you just trying to understand how pointers and dynamic allocation works, or is there something specific you are trying to do? We very rarely call delete explicitly in modern C++.


Hmm well I just needed to pass an address into a function so it doesn't make a copy of the object which I need to use. Just though a pointer would get the job done. I am just not going to call delete inside the function, but outside when I need to get rid of the object.

Thnx

Share this post


Link to post
Share on other sites
Quote:
Original post by Flopid
Quote:
Original post by Aardvajk

Are you just trying to understand how pointers and dynamic allocation works, or is there something specific you are trying to do? We very rarely call delete explicitly in modern C++.


Hmm well I just needed to pass an address into a function so it doesn't make a copy of the object which I need to use. Just though a pointer would get the job done. I am just not going to call delete inside the function, but outside when I need to get rid of the object.

Thnx


You don't need to dynamically allocate anything to accomplish that. Zahlman has already mentioned references:


class big_object
{
// lots of stuff, don't want to copy
};

void f(big_object &o)
{
// do stuff with o
}

void g()
{
big_object x; // just a normal local variable

f(x); // passed by reference, so no copy made

// x automatically destroyed when scope exits
}

Share this post


Link to post
Share on other sites
Quote:
Original post by Nanoha
someone has mentioned passning a poitner to a pointer and thats a good idea but does make your function code rather confusing later on with dereferances everywhere.

Actually no, because if you make it a habbit to dereference a parameter if the function is allowed to change it and keep up to this rule the code is actually more readable.


int *test = new int;
*test = 5;

Func_A(test);
Func_B(test);

void Func_A(int *in)
{
cout << *in;
}

void Func_B(int *&in)
{
cout << *in;
delete in;
in = NULL;
}


By just reading the code but not the function declarations you cannot figure out that Func_B actually messes with your pointer. If you force yourself to write code like so ...



int *test = new int;
*test = 5;

Func_A(test);
Func_B(&test);

void Func_A(int *in)
{
cout << *in;
}

void Func_B(int **in)
{
cout << *(*in);
delete *in;
*in = NULL;
}

... you can immediately see that Func_B dereferences your pointer and might mess around with it.

Share this post


Link to post
Share on other sites
More specifically, what you have here is a question of intent -- The function should call delete on the pointer if that is what you intended, and the context of your program says that this function should only be called with pointers which were allocated via new and also that callers understand that they are no longer responsible for managing the lifetime of the object (we don't want to call delete twice.

We call this concept "transferring ownership" -- which is to say that, if the intent is to indeed transfer ownership, then ownership is transferred from the caller to the function, along with the responsibility to ensure it is properly destructed/freed when it is no longer useful. This scenario is valid, but is far less common a simple reference through a pointer where ownership is not intended to be transferred.

There are many types of ownership semantics to choose from, and many of them are supported by the smart pointer classes supplied with the C++ standard library. Shared ownership (several objects owning a single, other object collectively) is facilitated by shared_ptr (as implemented by tr1 or boost) for example. shared_ptr is supplemented by weak_ptr to break cyclical references. Ownership which is transferred, and owned by the singular, current holder is supported by std::auto_ptr.

Finally, as someone has already mentioned, good C++ practice is to use references instead of pointers wherever possible -- references avoid copying objects to the stack just like pointers, but avoid all the dangers that pointer parameters bring along (pointer arithmetic, accidental deletion -- of course these things are still able to be done since you can take the address of a reference, but you can't *mistakenly* do them). We prefer to use pointers only when we need -- namely, when we desire to use pointer arithmetic, or passing an object instance is optional (via a null pointer -- null references are not allowed.) Also, while we're on the topic of good practices involving parameters, be sure to read up on the topic of const-correctness, which is especially important where pointers and references are involved.

Share this post


Link to post
Share on other sites
Ok I'll use a reference, and use const-correctness:

void myFunction(const MyObjectType &anObject)
{
...
}

My Java teacher once told us to use the "final" keyword for function parameters since the compiler does something in the background when the word is present. Does the Cpp compiler do something with "const" parameters? Just wondering.

Thnx

Share this post


Link to post
Share on other sites
Placing 'const' on a parameter like that tells the compiler that your intent is that the function will not change the value for which const is applied. This *can* allow the compiler to make more assumptions about what's going on, and more assumptions lead to a greater ability to optimize. In general, the more information you can give the the compiler regarding your intent (which compilers have a hard time determining on their own), the better the code that will be generated.

Also, take special care to know how to apply 'const' to pointers, because you have the constness of the pointed to object, as well as the constness of the pointer itself to consider.

Quote:
The C++ FAQ Lite 18.5
What's the difference between "const Fred* p", "Fred* const p" and "const Fred* const p"?

You have to read pointer declarations right-to-left.

const Fred * p means "p points to a Fred that is const" -- that is, the Fred object can't be changed via p.

Fred * const p means "p is a const pointer to a Fred" -- that is, you can change the Fred object via p, but you can't change the pointer p itself.

const Fred * const p means "p is a const pointer to a const Fred" -- that is, you can't change the pointer p itself, nor can you change the Fred object via p.


For references, you never have to deal with the consness of the reference itself, because references themselves are always const by their nature.

Share this post


Link to post
Share on other sites

This topic is 3039 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this