I am not sure what exactly the command delete does in c++? As far as I know, to free memory I have to use delete on objects, that I previously instantiated with new, like:
Obj* object = new Obj();
delete object;
But does delete actually deletes data from my objects, does it in any way alter the object and data inside the object itself OR does it just call the corresponding destructor? If the destructor is empty, does useing delete have any consequences to the object? The reason for this question is as follows:
If I just delete objects this way, the pointer gets invalid, and my program does crash. So, I think I should just call the destructor with the delete command and take further steps inside the destructor function do actually do the cleanup and to be sure that other objects refering to this object know that the pointer is truly invalid.
Besides calling the destructor, the delete operator deallocates the memory that was previously allocated by new. This memory goes back to the available pool of memory that can be allocated.
This also means that object now points to invalid memory and any attempt to use it, or any other pointer that pointed to it, will invoke undefined behavior. This is probably what is happening in your program.
So your progam most likely has an issue with who "owns" the pointer. You shouldn't be calling delete on a pointer value that is still being used elsewhere in your program.
Related
I have an object with a vector of pointers to other objects in it, something like this:
class Object {
...
vector<Object*> objlist;
...
};
Now, Objects will be added to list in both of these ways:
Object obj;
obj.objlist.push_back(new Object);
and
Object name;
Object* anon = &name;
obj.objlist.push_back(anon);
If a make a destructor that is simply
~Object {
for (int i = 0; i < objlist.size(); i++) {
delete objlist[i];
objlist[i] = NULL;
}
}
Will there be any adverse consequences in terms of when it tries to delete an object that was not created with new?
Yes, there will be adverse effects.
You must not delete an object that was not allocated with new. If the object was allocated on the stack, your compiler has already generated a call to its destructor at the end of its scope. This means you will call the destructor twice, with potentially very bad effects.
Besides calling the destructor twice, you will also attempt to deallocate a memory block that was never allocated. The new operator presumably puts the objects on the heap; delete expects to find the object in the same region the new operator puts them. However, your object that was not allocated with new lives on the stack. This will very probably crash your program (if it does not already crash after calling the destructor a second time).
You'll also get in deep trouble if your Object on the heap lives longer than your Object on the stack: you'll get a dangling reference to somewhere on the stack, and you'll get incorrect results/crash the next time you access it.
The general rule I see is that stuff that live on the stack can reference stuff that lives on the heap, but stuff on the heap should not reference stuff on the stack because of the very high chances that they'll outlive stack objects. And pointers to both should not be mixed together.
No, you can only delete what you newed
Object* anon = &name;
When name goes out of scope, you will have an invalid pointer in your vector.
What you're actually asking is whether it's safe to delete an object not allocated via new through the delete operator, and if so, why?
Unfortunately, this is obfuscated by some other problems in your code. As mentioned, when name goes out of scope, you're going to end up with an invalid pointer.
See zneak's answer for why your original question doesn't result in a safe operation, and why the scope for name actually matters.
This will not work - if you delete an object that wasn't allocated by new you've violated the rules or the delete operator.
If you need to have your vector store objects that may or may not need to be deleted, you'll need to keep track of that somehow. One option is to use a smart pointer that keeps track of whether the pointed to object is dynamic or not. For example, shared_ptr<> allows you to specify a deallocator object when constructing the shard_ptr<> and as the docs mention:
For example, a "no-op" deallocator is useful when returning a shared_ptr to a statically allocated object
However, you should still be careful when passing pointers to automatic variables - if the vector's lifetime is longer than the lifetime of the variable then it'll be refering to garbage at some point.
From my understanding, when you allocate objects on the heap you use
Object* dynamicobject = new Object();
When I call delete I go
delete dynamicobject
I'm confused because I delete the pointer to the instance of that object, but along my line of thinking, you need to actually delete the object in memory itself which requires you to dereference the pointer like
delete *dynamicobject
but this is incorrect.
If you want to change the object a pointer points to, it needs to be dereferenced, and I assumed that the same applied for deletion, but it seems only the pointer can be deleted.
If you do
delete *dynamicobject;
the value given to the delete operator is the value in the dynamic memory location, not the location itself. The delete operator needs to know where the dynamic memory is, so it can reclaim it.
For example, suppose you do:
int *dynamic_int = new int;
*dynamic_int = 10;
If you then did:
delete *dynamic_int;
the delete operator would receive the integer value 10. That doesn't provide the information it needs to reclaim the dynamic memory where that value is stored. But if you do
delete dynamic_int;
the delete operator receives the address of that dynamic memory, and it can reclaim it.
The operators are parallel. new returns a pointer to newly-allocated memory. delete takes a pointer to allocated memory and deletes it. In other words, delete (new ...()) works.
Maybe it would help to consider that delete fundamentally has to work with memory somehow, and not with an object, per se. Thus it needs not only the object but also the object's memory location.
I think you are thinking about destructing the object. When you call new, memory is allocated for the object and its address is returned as a pointer. That pointer is a unique identifier recording exactly which area of memory needs to be deallocated when the object is deleted.
So delete needs to be given the pointer to the memory to deallocate.
But that doesn't kill the object. Killing the object happens by running the destructor and this is where the pointer is dereferenced.
The destructor function is, of course ~Object() {}.
So delete will dereference the pointer to access the actual memory of the object by running the destructor function. After the destructor has run on the dereferenced object the memory address that the object occupied is released back to the runtime system.
So delete needs the pointer which gets dereferenced to destruct the object itself and is then used to determine exactly what memory to release.
delete dynamicobject; does not delete the pointer dynamicobject. Rather, it deletes the object that dynamicobject points to.
You don't have to (and can't) write delete *dynamicobject;, presumably for similar reasons to why you don't have to write dynamicobject = &new Object;.
You only deal in pointers, since dynamic memory allocation is just a big linked list of blocks. When you request a block of size n, the allocator searches the linked list for a block that satisfies the request. When the allocator finds the block, it returns a pointer to said block--that is, the address of the first byte in the block.
Freeing memory simply returns the block into the linked list, so that when you try to allocate memory again, that block may be reused.
All the allocator needs to know is the address of the first byte and the size. That's why it deals only in pointers.
Let say you have a class like this
class Level
{
public:
Level(std::string);
~Level();
private:
Bitmap* map;
}
and in the class you had this
Level::Level(std::string)
{
map = new Bitmap(path);
}
Was wondering do can you call
Level::~Level()
{
delete map;
}
As I was worried about if the class goes out of scope and I haven't deleted map. Then, wouldn't that cause a memory leak. Do I have to manually call to delete map. As I get crash if I call delete in the constructor in my program.
Like I could add a method to Level called say destroy map where I delete map. But, was wondering why I can't add delete into the destructor.
When the Level object goes out of scope, its destructor will be called, so deallocation of memory is useful because that memory is no longer needed. You can also use a unique_ptr, whereby memory-deallocation performed automatically.
This is why destructors stand for. Destructor is explicitly called when your object goes out of scope (memory residing on the stack objects) or when delete is called ( for dynamically allocated objects), so that the memory the object kept would be released. If you want to release member objects memory when destroyed, you can call the destructors of each object using delete (or delete[] for arrays). It is better that you use smart pointers, to avoid unintentional memory leaks and to ensure the memory is freed correctly in all cases, as they use RAII concept (RAII and smart pointers in C++).
Answers already have pointed out that you can trust your destructor to be called when your object goes out of scope. I won't reiterate that. I just wanted to point out that there is no need to allocate your Bitmap with new (unless you were using custom memory allocators, which is not the case here). You can construct it with an initialiser list:
class Level
{
public:
Level(std::string);
private:
Bitmap map;
};
Level::Level(std::string)
: map(path)
{
}
Now it has automatic scope and you don't have to worry about your destructor.
That's basically right.
However:
You need to make sure you create a copy constructor and assignment operator too, if you are managing memory this way. (That's where your crash comes from.)
An alternative, the best way, is to use RAII and store not a raw pointer but a scoped or automatic pointer. Or even just a directly encapsulated object! Then you don't need the delete at all.
As I was worried about if the class goes out of scope and I haven't deleted map. Then, wouldn't that cause a memory leak.
You're right - you should delete map exactly as your code does. But, you should also make your object non-copyable (derive from boost or C++11 noncopyable base classes, or add a private declaration (with no definition/implementation) of the operator= copy assignment and copy constructor. Otherwise, if you (deliberately or accidentally or incidentally - e.g. when storing your object in a container that sometimes copies it around, such as a std::vector) copy your object, then the first copy destructored will delete the map, any other copy that tries to use it will likely crash, and any other copy's destructor that also tries to delete it will also have undefined behaviour.
Do I have to manually call to delete map.
Yes, in your code you do.
A better alternative is to use a smart pointer whose own destructor will delete the pointed-to object.
As I get crash if I call delete in the constructor in my program.
Well, if you call delete after the new, then the constructor won't crash, but you wouldn't have a map object to use after the constructor returns, and if you then try to delete it again in the destructor the you get undefined behaviour which may well manifest as a crash.
If you want to delete the map earlier than the destructor sometimes, you can set the pointer to NULL so that a future delete will do nothing safely. You should then check for NULL before trying to use the map.
Like I could add a method to Level called say destroy map where I delete map. But, was wondering why I can't add delete into the destructor.
As above, you can have destroy_map, but it must coordinate with the destructor.
When there's no compelling reason to do otherwise, it's better to make the map member data, not storing it by reference. When a pointer is useful, use a smart pointer if at all possible. If you want to implement explicit manual memory management, be wary of the issues above.
This is an unusual way to do it. Normally, an object's lifetime is determined by factors outside of the object.
But in fact MFC used to (still does?) do exactly this when a Window is being destroyed. (In response to WM_NCDESTROY, I believe.) This ensures you don't have the Window instances leaking memory after the window is gone.
So I would say it is valid in some cases. You might call it class suicide!
Suppose I am writing a C++ class. The class has the following fields:
An integer.
a C++ string
dynamically resizable integer array and a pointer to it.
In the destructor, I know I have to delete anything that I had earlier claimed by calling new. In this case, I know I have to free the space I used for the int array. What about the string's memory? I know I'm not responsible for releasing its memory, because I didn't call new to allocate it, but how does it get freed? When does C++ call its destructor?
What about the string's memory? I know I'm not responsible for releasing its memory, because I didn't call new to allocate it, but how does it get freed?
Your class's destructor implicitly calls std::string's destructor which in turn handles the freeing of its own resources. Nothing else to worry.
When does C++ call its destructor?
When your class' object's destructor is called. That means when that object goes out of scope or delete has been called on a pointer to it when it has been created by new.
I somehow understand your problem. You may think that new recursively news the members of your class. No. It doesn't do it that way. Unless your class itself does new on the member variables will you need to call delete on them.
Destructors of member variables are automatically called once the instance destructor has completed.
That memory is reclaimed when the variable goes out of scope.
I have an object with a vector of pointers to other objects in it, something like this:
class Object {
...
vector<Object*> objlist;
...
};
Now, Objects will be added to list in both of these ways:
Object obj;
obj.objlist.push_back(new Object);
and
Object name;
Object* anon = &name;
obj.objlist.push_back(anon);
If a make a destructor that is simply
~Object {
for (int i = 0; i < objlist.size(); i++) {
delete objlist[i];
objlist[i] = NULL;
}
}
Will there be any adverse consequences in terms of when it tries to delete an object that was not created with new?
Yes, there will be adverse effects.
You must not delete an object that was not allocated with new. If the object was allocated on the stack, your compiler has already generated a call to its destructor at the end of its scope. This means you will call the destructor twice, with potentially very bad effects.
Besides calling the destructor twice, you will also attempt to deallocate a memory block that was never allocated. The new operator presumably puts the objects on the heap; delete expects to find the object in the same region the new operator puts them. However, your object that was not allocated with new lives on the stack. This will very probably crash your program (if it does not already crash after calling the destructor a second time).
You'll also get in deep trouble if your Object on the heap lives longer than your Object on the stack: you'll get a dangling reference to somewhere on the stack, and you'll get incorrect results/crash the next time you access it.
The general rule I see is that stuff that live on the stack can reference stuff that lives on the heap, but stuff on the heap should not reference stuff on the stack because of the very high chances that they'll outlive stack objects. And pointers to both should not be mixed together.
No, you can only delete what you newed
Object* anon = &name;
When name goes out of scope, you will have an invalid pointer in your vector.
What you're actually asking is whether it's safe to delete an object not allocated via new through the delete operator, and if so, why?
Unfortunately, this is obfuscated by some other problems in your code. As mentioned, when name goes out of scope, you're going to end up with an invalid pointer.
See zneak's answer for why your original question doesn't result in a safe operation, and why the scope for name actually matters.
This will not work - if you delete an object that wasn't allocated by new you've violated the rules or the delete operator.
If you need to have your vector store objects that may or may not need to be deleted, you'll need to keep track of that somehow. One option is to use a smart pointer that keeps track of whether the pointed to object is dynamic or not. For example, shared_ptr<> allows you to specify a deallocator object when constructing the shard_ptr<> and as the docs mention:
For example, a "no-op" deallocator is useful when returning a shared_ptr to a statically allocated object
However, you should still be careful when passing pointers to automatic variables - if the vector's lifetime is longer than the lifetime of the variable then it'll be refering to garbage at some point.