I have many boost::shared_ptr<MyClass> objects, and at some point I intentionally want to delete some of them to free some memory. (I know at that point that I will never need the pointed-to MyClass objects anymore.) How can I do that?
I guess you can't just call delete() with the raw pointer that I get with get().
I've seen a function get_deleter(shared_ptr<T> const & p) in boost::shared_ptr, but I'm not sure how to use it, and also it says experimental right next to it. (I think I have Boost 1.38.)
Maybe just assign a new empty boost::shared_ptr to the variable? That should throw away the old value and delete it.
You just do
ptr.reset();
See the shared_ptr manual. It is equivalent to
shared_ptr<T>().swap(ptr)
You call reset on every smart pointer that should not reference the object anymore. The last such reset (or any other action that causes the reference count drop to zero, actually) will cause the object to be free'ed using the deleter automatically.
Maybe you are interested in the Smart Pointer Programming Techniques. It has an entry about delayed deallocation.
If you want to be able to intentionally delete objects (I do all the time) then you have to use single ownership. You have been lured into using shared_ptr when it is not appropriate to your design.
The whole point of boost::shared_ptr<T> is that the pointee object will be deleted exactly at the moment when no shared_ptr<T>s point at it -- that is, when the last shared_ptr<T> pointing at this object goes out of scope or is reassigned to point to a different object. So, all you have to do to delete an object is make sure there are no shared_ptr<T>s pointing at it. E.g. if you only have a single shared_ptr<T> called p pointing at an object, either let it fall out of scope, or call p.reset() (equivalent to p = NULL for a plain pointer), or assign it to point at something else.
If you have two shared_ptr<T>s pointing at the object, you'll need to reassign both of them.
EDIT: Thanks to dehmann for pointing out that p = NULL; is not actually valid code for a shared_ptr<T>... :)
What you want to do is return weak references using boost::weak_ptr that can be converted to a shared_ptr when needed. This can allow you to control the lifetime of the object in the shared_ptr and those that want to access it can hold onto the weak_ptr and try to convert to a shared_ptr. If that convert fails, then they can re-query and bring the object back into memory.
Related
What happens if a C/C++ API returns a raw pointer from an internally used shared_ptr, then the shared_ptr gets "deleted"? Is the raw pointer still valid? How can the API developer clean up the raw pointer when it's not in their control anymore?
As an example:
MyClass* thisReturnsAPtr()
{
std::shared_ptr<MyClass> aSharedPtr = std::make_shared<MyClass>(MyClass);
return aSharedPtr.get();
}
If there are no other shared_ptr around anymore that still hold a reference to the object and, thus, keep the object alive, then the object will be destroyed, the memory freed, and any still existing pointer that pointed to that object will become a dangling pointer.
In your example above, the pointer returned by the function thisReturnsAPtr is guaranteed to be an invalid pointer…
It can sometimes be useful to think of smart pointers as a delayed delete mechanism. What I mean by that is that if you allocate a class and give it to a smart pointer you are basically asking the smart pointer class to delete that pointer sometime in the future. For a shared_ptr that time in the future is when no more shared_ptrs exist for it.
Applying this to your code, you create a shared_ptr. You then return the raw pointer. Then your function ends and the only shared_ptr to that pointer gets destroyed and so the underlying class is deleted.
This makes your question "If I new a class and delete it then return the original pointer what happens". Which is a lot easier to answer and the answer to that is "badness". There are many answers to this question on stack overflow - such as C++ delete - It deletes my objects but I can still access the data?
"What happens to a raw pointer if it's shared_ptr is deleted?" - Nothing. It just becomes invalid to subsequently use that pointer.
"a C/C++ API returns a raw pointer from an internally used shared_ptr, then the shared_ptr gets "deleted"? Is the raw pointer still valid?"
No. It is not valid to then use the raw pointer. And the raw pointer does not change (to nullptr) to indicate that the pointed-to object has been deleted.
It is your responsibility to ensure, that if something like that happens, you do not use the raw pointer after it has been invalidated. How you do that is up to you - the language doesn't care/help you.
Using the raw pointer after the object it points to has been deleted, is Undefined Behaviour.
I'd like to enforce that an object should exist before passing it to a function:
void Class::setStoredObject(MustExist& obj) {
stored_object = &obj;
}
// Lifetime of ptr is my responsibility
std::unique_ptr<MustExist> ptr = std::make_unique<MustExist>();
classObject.setStoredObject(*ptr);
anyway I also need to store that object (big one) by reference or address so I usually grab a pointer to it.
Is this safe to do? I.e. getting the address of a reference to refer to the original pointed-to object.
Alternatively, any other/better way that I could achieve this?
There's nothing wrong with this, per se. Of course, if the original object goes out of scope and gets destroyed, the saved pointer to the object will no longer be valid.
The safest way to ensure that you get an existing object and that it won't be deleted without a possibility to check this, is by instantiating and passing a shared_ptr. This way you can choose to store the shared_ptr so you're sure it won't disappear (but then you need some clean up code) or store as weak_ptr so you can only use it when it still exists.
Storing raw pointers of objects controlled by smart pointers can lead to very subtle issues, that are difficult to trace back to code.
In general, it is not a good design to get and to use a raw pointer out of std::unique_ptr as it breaks all the idea of it.
Dereferencing ptr and passing the object by reference is not a good semantic for what you are trying to do.
If the caller context needs the unique_ptr you should use:
void Class::setStoredObject(std::unique_ptr<MustExist> obj_ptr)
and do the call
classObject.setStoredObject(std::move(ptr));
expressing the fact that the calling context is giving away ownership.
Otherwise you can give up the unique_ptr altogether (its existence is not justified in your example). In this case I would consider either of:
void Class::setStoredObject(const MustExist& obj) // ok for copy
void Class::setStoredObject(MustExist&& obj) // move semantics, expressing the fact that the caller is done using the object.
I'm trying to refactor a section of code into a separate object/file. To maintain the same behavior, my code needs to use pointers to key components in the original file, which are declared as unique_ptrs.
I was thinking to extract the raw pointers and pass them to my object since my portion isn't responsible for deleting any pointers. (I hope I'm understanding ownership semantics correctly, still relatively new to C++). The only caveat is that I need to replicate unique_ptr::reset's behavior. Will this code do the same thing reset does?
template <typename Type>
void reset(Type* ¤t_ptr){
Type* old_ptr = current_ptr;
current_ptr = new Type();
if(old_ptr != null)
delete old_ptr;
}
If you need to call reset then you are in fact actually deleting pointers, and doing so outside the context of the unique_ptr's destructor is a recipe asking for disaster (even if your code appears to work it may still be undefined behavior).
If in fact all you need is to dereference (primarily * and ->) the unique_ptr then you should pass and use a reference to the object in your new code, making sure that the unique_ptr can't die while you're using the reference.
If you need to reassign or reset the smart pointer you'll need an alternate approach, but you didn't supply enough information in the question to help scope out such an alternate approach.
No, that's not what reset() does.
As pointed out in the comments, the features of smart pointers are about ownership, not pointers themselves. Ownership means responsibility, so if a unique_ptr owns an object, it is its "job" to delete it when the unique_ptr dies itself. shared_ptr are a little more complex, but they are also all about deleting the object "when the time comes", and taking that responsibility off of you, the programmer.
unique_ptrs are unique, that is, no two unique_ptrs should ever own the same object.
Now, the reset() method is a way of saying "hey, unique_ptr, I've got a new pointer for you to manage, so destroy the old one (if you had any) and take ownership of this new one that I'm giving you. From now on, this is the one you'll destroy when you die yourself."
This operation has no meaning with raw pointers, since they do not hold any ownership and won't kill themselves off at the right time or anything like that.
So, comparing that with your code, the similarity is that the old pointer is indeed deleted. But apart from the essence being missing (that is, the raw pointer won't remember to delete itself and does not hold ownership), the normal reset() is given a pointer, it does not create a new object by itself.
I have a small C++ program where I create two objects of a Person class. This class has char *m_szFirstName and char *m_szLastName for data.
I then I assign one object to another, causing both object's data members to point to same location.
In the destructor, I delete what memory I had allocated for the first object and assign NULL values to the pointers. Something like this.
if (m_szFirstName!= NULL)
{
delete [] m_szFirstName;
m_szFirstName = NULL;
}
Then when I go to delete memory for the second object, the check for NULL does not work and when I delete memory, I get a crash. From debugger, it show that my pointer is not NULL. It has 0xfeee.
I am aware that memory was already deleted before and should not be delete. However, I don't know how to check whether I should delete memory or not.
Reason for Crash:
You should follow the Rule of Three to avoid this problem of dangling pointers.
If you need to explicitly declare either the destructor, copy constructor or copy assignment operator yourself, you probably need to explicitly declare all three of them.
In your case You do not define a copy assignment operator thus leading to shallow copy of the pointer.
Suggested Solution:
If you can use std::string instead of char * just simply use std::string, it has the first and foremost preference over any kind of silly pointer stuff.
You can avoid all the funky pointer stuff by using std::string.
If you can't read on and the following suggestion applies to any class pointer member in general.
Note that the ideal solution here is to not use raw pointers at all, Whenever you use raw pointers you are forced to manually manage the resources acquired by them, it is always difficult and error prone to manually manage resources.So the onus is to avoid it.
To do so, You should use a Smart pointer which will manage the dynamic memory of the pointer implicitly.Using a smart pointer will ensure that the dynamic memory is implicitly released after usage & you do not have to manually manage it.
The scenario you have is the very reason that in C++ you should rely on RAII rather than manual resource management & using a Smart pointer is the way to go about in your case.
Caveat:
Note that I restrained myself from suggesting which smart pointer to use because the choice rather depends on the ownership and lifetime of the elements involved, which is not clear from the data provided in the Question.So I will suggest reading,
Which kind of pointer do I use when?
to make your choice of the smart pointer to use.
With
if (m_szFirstName!= NULL)
{
delete [] m_szFirstName;
m_szFirstName = NULL;
}
You only set m_szFirstName to point to NULL, not m_szLastName. This means you have to have some way to keep track of the fact they point to the same location. Is there a reason they point to the same location? Could you copy the name instead of pointing the pointers to the same place?
If you need the two pointers to shared the same data, I would have a look at std::tr1::shared_ptr, which will solve this issue for you by keeping track of the number of references and deleting when the number of references reaches 0.
Don't delete it again, if (m_szFirstName == m_szLastName).
But this will give you a memory leak (when you assign one pointer to other).
When you have two pointers pointing to the same location (after you assigned the first one to the second one), you have two pointers pointing at the same address. Deleting one frees the memory pointed to by both of them. But setting one to NULL doesn't alter the other pointer. The same happens if you have two integers, for example.
int a = 3;
int b = a;
Now if you run
a = 0;
the value of b doesn't change. The same way your second pointer doesn't change when you alter the first one (but when you alter the memory pointed to by either pointer, you can see the effect through the other as well).
Your problem is a classic C/C++ problem which is known as "Dangling Pointer" problem. Dereferencing the dangling pointer has resulted in the crash. The problem is about reference counting. Once you assign the same memory to the second pointer then the reference count should be 2. So if you delete one pointer reference count should become 1 and your memory should not be deallocated or freed unless count is 0. At 0 it can be garbage collected.
Now there are good answers above to solve your problem. Since you are using C++ so you can use something like an auto_ptr (OR shared_ptr). They provide what I had mentioned above, the reference counting stuff and even you need not worry about deleting or freeing your objects, these classes would take care. They work on simething known as RAII pattern where a destructor is auto-magically called when the object on the stack goes out of scope.
Just stop setting pointers to NULL when you have deleted the object. As you can see, it just leads to pain. You cannot assume that because the pointer is not-NULL, it has not been deleted already.
You can use any sensible pattern you want to avoid this problem. For example, Boost's shared_ptr is a great choice.
If I have a pointer pointing to a specific memory address at the heap. I would like this same pointer to point to another memory address, should I first delete the pointer? But, in this case am I actually deleting the pointer or just breaking the reference (memory address) the pointer is pointing at?
So, in other words, if I delete a pointer, does this mean it doesn't exist any more? Or, it is there, but not pointing to where it was?
The syntax of delete is a bit misleading. When you write
T* ptr = /* ... */
delete ptr;
You are not deleting the variable ptr. Instead, you are deleting the object that ptr points at. The value of ptr is unchanged and it still points where it used to, so you should be sure not to dereference it without first reassigning it.
There is no requirement that you delete a pointer before you reassign it. However, you should ensure that if you are about to reassign a pointer in a way that causes you to lose your last reference to the object being pointed at (for example, if this pointer is the only pointer in the program to its pointee), then you should delete it to ensure that you don't leak memory.
One technique many C++ programmers use to simplify the logic for when to free memory is to use smart pointers, objects that overload the operators necessary to mimic a pointer and that have custom code that executes automatically to help keep track of resources. The new C++0x standard, for example, will provide a shared_ptr and unique_ptr type for this purpose. shared_ptr acts like a regular pointer, except that it keeps track of how many shared_ptrs there are to a resource. When the last shared_ptr to a resource changes where it's pointing (either by being reassigned or by being destroyed), it then frees the resource. For example:
{
shared_ptr<int> myPtr(new int);
*myPtr = 137;
{
shared_ptr<int> myOtherPtr = myPtr;
*myPtr = 42;
}
}
Notice that nowhere in this code is there a call to delete to match the call to new! This is because the shared_ptr is smart enough to notice when the last pointer stops pointing to the resource.
There are a few idiosyncrasies to be aware of when using smart pointers, but they're well worth the time investment to learn about. You can write much cleaner code once you understand how they work.
When you delete a pointer you release the memory allocated to the pointed to object. So if you just want your pointer to point to a new memory location you should not delete the pointer. But if you want to destroy the object currently it is pointing to and then then point to a different object then you should delete the pointer.
xtofl, while being funny, is a bit correct.
If YOU 'new' a memory address, then you should delete it, otherwise leave it alone. Maybe you are thinking too much about it, but you think about it like this. Yea, the memory is always there, but if you put a fence around it, you need to take the fence down, or no one else can you it.
When you call delete you mark the memory pointed to by the pointer as free - the heap takes ownership of it and can reuse it, that's all, the pointer itself is usually unchanged.
What to do with the pointer depends on what you want. If you no longer need that memory block - use delete to free the block. If you need it later - store the address somewhere where you can retrieve it later.
To answer your question directly, this has been asked before. delete will delete what your pointer points to, but there was a suggestion by Bjarne Stroustrup that the value of the pointer itself can no longer be relied upon, particularly if it is an l-value. However that does not affect the ability to reassign it so this would be valid:
for( p = first; p != last; ++p )
{
delete p;
}
if you are iterating over an array of pointers, all of which had been allocated with new.
Memory management in C++ is best done with a technique called RAII, "resource acquisition is initialization".
What that actually means is that at the time you allocate the resource you immediately take care of its lifetime, i.e. you "manage" it by putting it inside some object that will delete it for you when it's no longer required.
shared_ptr is a technique commonly used where the resource will be used in many places and you do not know for certain which will be the last one to "release" it, i.e. no longer require it.
shared_ptr is often used in other places simply for its semantics, i.e. you can copy and assign them easily enough.
There are other memory management smart pointers, in particular std::auto_ptr which will be superceded by unique_ptr, and there is also scoped_ptr. weak_ptr is a methodology to be able to obtain a shared_ptr if one exists somewhere, but not holding a reference yourself. You call "lock()" which gives you a shared_ptr to memory or a NULL one if all the current shared pointers have gone.
For arrays, you would not normally use a smart pointer but simply use vector.
For strings you would normally use the string class rather than think of it as a vector of char.
In short, you do not "delete a pointer", you delete whatever the pointer points to.
This is a classical problem: If you delete it, and someone else is pointing to it, they will read garbage (and most likely crash your application). On the other hand, if you do not and this was the last pointer, your application will leak memory.
In addition, a pointer may point to thing that were not originally allocated by "new", e.g. a static variable, an object on the stack, or into the middle of another object. In all those cases you're not allowed to delete whatever the pointer points to.
Typically, when designing an application, you (yes, you) have to decide which part of the application owns a specific object. It, and only it, should delete the objects when it is done with it.