When using list what are the good habits to manage memory,
dynamic allocation and release (free) wheneve we dont need it anymore. To keep program light and avoid memory leaks ensure a good memory managment (i now it's a wide question)
how to initialize a list of pointers to objects initially with N items ? should i use the operator new to allocate memory?
if i want to delete completely (free) an item from a list and program memory space, should i use pop or remove or erase ? differences?
should i use operator delete while iterating a list or .erase .remove is enough to free space ?
.
class myclass { /* whatever attributes, methodes */ };
list<myclass *> lst (5); //5 pointers will be NULL this way
for (list<myclass *>::iterator it=lst.begin(); it != lst.end(); it++) {
myclass *obj= *it;
delete obj; //error
it = lst.erase(it);
}
C++ has value semantics. A list owns the objects on it. This is true whether it's a list of int (built-in type), std::string (library type) or myclass (yours). Make sure that your class can be copied (or at least moved, but that's an advanced topic). Also make sure that your class destructor works properly, because list::clear will call it.
Do not try to use lists of pointers, initially. When you do, use lists of smart pointers, but that is already an advanced topic. Lists of "dumb" pointers should be avoided outright.
Though I think you should listen to what everyone else said, I figured I would still answer your questions so you know the answer should you need to know them. Smart pointers are definitely best to use nowadays, but when I learned pointers in C++, I initially used new/delete and I feel it helps you understand better than just going straight to smart pointers (I know you said you don't know what they are, so they just manage the memory for you).
how to initialize a list of pointers to objects initially with N items ? should i use the operator new to allocate memory?
As you did, list<myclass *> lst (5) would be just fine to make your list of pointers, and yes, you should use new for each of the elements in the list in order to allocate memory there. For example,
list<myclass*>::iterator it = lst.begin();
*it = new myclass();
if i want to delete completely (free) an item from a list and program memory space, should i use pop or remove or erase ? differences?
To get rid of an element from the list, you can use the list's erase function found here: http://www.cplusplus.com/reference/list/list/erase/
That will remove the element from the list, however be careful here if using pointers, because you'll need to make sure that you free the pointer that the list node was holding before you erase this node (see below)
should i use operator delete while iterating a list or .erase .remove is enough to free space ?
.erase will delete the element from the list, but it will not free the pointer for you, you will would explicitly need to do something like this.
list<myclass*> lst(5);
list<myclass*>::iterator it = lst.begin();
*it = new myclass();
// and when you're ready to delete a node
if(*it != NULL)
delete *it;
lst.erase(it);
Also, in your for loop, be sure to check, as I do, if the pointer is NULL before deleting it. This is likely why you got an error on the delete call. Since it is not allowed to store memory at NULL, it is clearly not allowed to delete the memory there. That will give you a segmentation fault. It's always good to check for NULL before deleting just in case unless you are positive it will be holding data.
Hope this helps. It's not the best way to do it with newer versions of C++ available, but it should answer your question as asked.
how to initialize a list of pointers to objects initially with N items ? should i use the operator new to allocate memory?
Don't. Let the list handle the allocation and deallocation.
lst.push_back(myclass());
If you have a number of items to go into the list, you can take advantage of initializers. The following uses a myclass constructor that takes a string and an int as an example.
list<myclass> lst {{"one", 1},{"two", 2},{"three", 3}};
If this is an assignment which requires pointer use, definitely use new rather than malloc and it's family to allocate storage, but consider this a last resort.
Preferred would be to use a smart pointer. The big two of these are unique_ptr and shared_ptr.
list<unique_ptr<myclass>> lst;
lst.push_back(unique_ptr<myclass>(new myclass()));
or in C++14 or newer,
lst.push_back(make_unique<myclass>());
The unique_ptr automatically destroys the myclass when removed from the list.
But I see no advantage to this over the list directly containing myclass unless myclass is the base class of a class hierarchy. If you are in the early stages of learning C++, do some reading and practice of the basics before going this route.
list<shared_ptr<myclass>> lst;
lst.push_back(shared_ptr<myclass>(new myclass()));
Makes a reference-counted my class that can be shared with others. When every user has disposed of their shared_ptr, the myclass will be destroyed. This is great for systems with callbacks. The callback object will be there when the callback fires, preventing all sorts of fun segfaults. The downside is the lifetime of the object is blurred. When it is destroyed depends on the outstanding shared_ptrs.
Do not allow circular references of shared_ptrs, as the reference count will never drop to zero. There might be some really sneaky code built in to assist here, but I wouldn't count on it. Bad program design anyway.
Raw pointer with new. Just don't do this. You have better, safer options.
lst.push_back(new myclass());
if i want to delete completely (free) an item from a list and program memory space, should i use pop or remove or erase ? differences?
remove doesn't exist for list. Pop, depending on which one you use, either removes the first or last element. Use pop if the list represents a queue or a stack. erase can remove any element, so long as you know where it is. Finding it may require a search.
With a stored object, list<myclass> you might not get any memory back. The list may save the allocated RAM so it doesn't have to ask for it again later. Frankly I'm not sure what the standard's policy is for lists. For vectors, the object is destroyed, but the space remains allocated unless you manually force a resizing. I believe list behaves the same way because of the presence of the resize method and the wording of the documentation.
If you have a raw pointer, you must delete it, then remove it from the list. You can't do it in the other order because once removed from the list the pointer is inaccessible and the RAM is lost to you. Yeah, you can copy the pointer, then remove it from the list, then delete the copy, but why go to the extra effort? I believe the pointer will still be allocated in the list, but will be inaccessible and awaiting reuse.
If you use a unique_ptr, the unique_ptr handles the disposal for you. With a shared_ptr, disposal is also handled for you, but you don't necessarily know when. Another copy of the shared_ptr may exist, blocking destruction.
should i use operator delete while iterating a list or .erase .remove is enough to free space ?
Covered above in my answer to 2. With a pointer, removal from the list only removes the pointer to myclass and leaves you without a pointer to myclass and the RAM is lost. With a smart pointer, the myclass is destroyed by the smart pointer with no further effort required.
But you may not get any noticeable amount of RAM back if it is being held by the list for reuse.
Related
I'm new to C++ and i'm not absolutely sure how to deal with arrays and pointers in a safe way. In my class I got a member called items:
Item * items;
in my class method called read() I open a file and read the items from this file. I allocate the space accordingly:
items = new Item[item_count];
item_count is given as a variable in the file and is read in advance before creating any items. In the deconstructor in my class I release the memory like this again:
delete[] items;
But if i call the method read() twice before my deconstructor is executed the memory for the first array will not be released properly. I would like to release it in the read method in advance before allocating new memory. But how do I check if some memory is already allocated for the array items?
EDIT: I know there are many other possibilities out there with more 'modern' approachs and more comfortable solutions. But in this case we where explicitly told to use pointers and arrays (education purpose only).
In modern C++, "the safe way" is to avoid raw pointers and raw arrays entirely.
Declare your variable like this:
std::vector<Item> items;
Allocate the space like this:
items.resize(item_count);
In the deconstructor in your class, no code is necessary to release this memory. It's handled automatically.
The reuse of items that you describe in your question will work.
Unless you have some strong reason not to do so, just use std::vector for arrays in C++:
#include <vector> // for std::vector
....
std::vector<Item> items;
In this way, you don't have to explicitly call delete[] to release vector items' resources; it's just done automatically thanks to vector's (and Items') destructors.
This helps building code that is structurally incapable of leaking resources.
You can create a vector of itemCount Items using something like:
std::vector<Item> items(itemCount);
or you could dynamically resize the vector using its resize() method, e.g.:
items.resize(itemCount);
In c, normally you initialize the pointer to NULL so you can check whether or not it points to valid memory, and then after deallocation you immediately set it back to NULL.
Failing to do so, may cause problems, like dereferencing an already deallocated pointer (they're called dangling pointers), so you must be careful.
In c++ you should use nullptr which is equivalent to c's NULL.
Also, there are smart pointers in c++, i.e. pointers that can do this automatically.
Edit: (the answer above was edited) as suggested from the comments, and although this same idea is correct, you should not use NULL in c++, instead use nullptr which has the same functionality, but takes care about the fact that in c++ void * is not automatically converted to any other pointer type like in c.
This Stack Overflow Answer has the details, and also an example that would definitevely convince you and me to use nullptr instead.
Suppose there's a vector of Items
vector<Item*> items; //{item1, item2, item3}
Then, in other part of the code,
items[1]->suicide();
where the suicide function is:
void Item::suicide()
{
delete this;
}
What is items vector size and how it's arrangement now?
It is okay to do this?
Edit (may I ask an additional question?): If the desired arrangement of the output is {item1, item3}, size is 2, and no dangling pointer, how to do it in a self-destructing way (from the item2 itself)?
Edit 2 : Thanks for all the answers! Awesome. So I finally decided and found the way to do it from outside of the object because it was a bad practice and unnecessarily complicated
What is items vector size and how it's arrangement now? The same. The function call does not change the vector contents nor size at all. It just frees the memory the pointer is pointing to.
Is it okay to do this? More precisely: Is it legal C++? Yes. Is it good style programming? No. Let me elaborate on the latter:
There should be a separation of concerns: Who's responsible for memory management? The container or the user of the class Item or the class Item itself?
Typically the container or user should do that, because he knows what's going on.
What's the way to do that? Memory management in modern and safe C++ code is mostly done using smart pointers like std::shared_ptr and std::unique_ptr and containers like std::vector and std::map.
If the class Item is a value type (that means you can simply copy it and it has no polymorphic behavior in terms of virtual functions), then just use std::vector<Item> instead for your code. Destructors will be called automatically as soon as an element is removed from the container. The container does it for you.
If the class Item has polymorphic behavior and can be used as a base class, then use std::vector<std::unique_ptr<Item>> or std::vector<std::shrared_ptr<Item>> instead and prefer the std::unique_ptr solution, because it adds less overhead. As soon as you stop referring to an object, it will be deleted automatically by the destructor of the smart pointer you are using. You (almost) don't need to worry about memory leaks anymore.
The only way you can produce memory leaks is that you have objects that contain std::shared_ptrs that refer to each other in cyclic way. Using std::unique_ptrs can prevent this kind of trouble. Another way out are std::weak_ptrs.
Bottom line: Don't provide a function suicide(). Instead put the responsibility solely into the hands of the calling code. Use standard library containers and smart pointers to manage your memory.
Edit: Concerning the question in your edit. Just write
items.erase( items.begin() + 1 );
This will work for all types: std::vector of values or pointers. You can find a good documentation of std::vector and the C++ Standard library here.
The suicide member doesn't change the vector. So the vector contains an element which is an invalid pointer and formally you can't do much with an invalid pointer, even copying or comparing it is undefined behavior. So anything which access it, included vector resizing, is an UB.
While any access if formally UB, there is a good chance that your implementation doesn't behave strangely as long as you don't dereference the pointer -- the rationale for making any access UB is machines where loading an invalid pointer in a register can trap and while x86 is part of them, I don't know of widespread OS working in this mode.
Your suicide function does not to anything with the Items vector, let alone it knows anything about it. So from the vector's point of view: nothing changes when you call the function and it's ok to do that.
The pointer will become invalid, that's all. You should be careful to not to delete it again. vector<Item*> will NOT delete elements on its own.
The vector has no idea what you're doing elsewhere in the code, so it'll keep a dangling pointer to the original Item.
"Is it OK do do that?"
After suiciding the item, you should adjust the vector manually to no longer keep that dangling pointer.
That's ok in case of vector of pointers as vector will not call Item's destructor. But you have to somehow know which pointers are still valid.
If you are storing Items in vector by value, calling Item's destructor is not ok. When vector will be destroyed or cleared, it will call item's destructor again, causing application crash.
Wow, It seems that you make a typing error. It should be vector<Item *> Items;
As to your question:
the size of vector Items does not change, means that, it still has three pointers to Item objects.
the content of the vector does not change:
before Items[1]->suicide() , Items[0] = 0x000001, Items[1] = 0x000005, Items[2] = 0x000009
after Items[1]->suicide(), Items[0] = 0x000001, Items[1] = 0x000005, Items[2] = 0x000009
It's definitely OKAY to do so.
Besides, the vector will manage its memory automatically, when you push some elems into it while the capacity is not enough, it will reallocate a larger space, BUT, when you pop some elems or erase some elems, it will never give the redundant memory to the system.
The code of Items[1]->sucide() just return the memory held or pointed by the pointer Items[1] to the system, it will do nothing on the pointer itself, Items[1] still holds the same value, but point an unsafe area.
Unexpectedly, you have made a Design Pattern, suppose you want to design a class and you ONLY allow allocate any object of it on the Heap, you may write the following code:
class MustOnHeap
{
private:
~MustOnHeap() { // ...}
public:
void suicide() { delete this;}
};
Then ,the class can not have any instance that is alloacated on the stack, because the destructor is private, and the compiler must arrange the calling of destructor when the object walk out its scope.
Therefor, you must allocate them on the heap, MustOnHeap* p = new MustOnHeap; and then destroy it explicitly : p->suicide();
I have a private field
std::map<std::string, std::multiset<GraphObject*>>* the_Map;
How can I allocate memory for it and insert a GraphObject?
Do I have to use the new operator?
the_Map = new map<string,multiset<GraphObject*>>;
And how can I insert a new GraphObject?
It's part of a datastructure and I really need a pointer to a map.
How can I allocate memory for it and insert a GraphObject?
It doesn't want to be a pointer at all; just make the map itself a member of the class and memory allocation will happen automatically.
Correctly inserting an object is rather fiddly, since you're storing pointers there too. If it doesn't need to be a pointer, then storing objects would make your life much easier. If it really does have to be a pointer (e.g. because GraphObject is a polymorphic base class), I would recommend storing smart pointers: std::unique_ptr, or std::tr1::shared_ptr or boost::shared_ptr if you're stuck in the past.
If you really, really need to use raw pointers for some insane reason, then the closest you can get to an exception-safe insertion is probably:
GraphObject * object = new Whatever(...);
try {
the_Map[key].insert(object);
} catch(...) {
delete object;
throw;
}
or if you don't care about the possiblity of memory leaks on insertion failure:
the_Map[key].insert(new Whatever(...));
Also don't forget to delete each object when you remove it; that won't happen automatically.
I really need a pointer to a map.
No you don't. But if you really believe you do, and want to ignore everyone's advice not to, then you'll need an actual map to point to. I would recommend that you make this map a member of the class, so that its lifetime is managed automatically.
If you really want to make life difficult for whoever maintains the code, then I suppose you could allocate one with new. In that case, remember to delete it when you've finished with it; probably in the class destructor. And if you do that, remember the Rule of Three and implement or delete the copy constructor and copy-assignment operator, since the default implementations will do the wrong thing.
Why you're storing a ::std:multiset of GraphObject *'s is a bit obscure, but lets roll with that.
This is an answer that is really trivially answered by documentation, but there is no question too dumb for StackOverflow, so...
the_Map = new map<string,multiset<GraphObject*>>;
That is indeed how you allocate memory for your map. It's generally not a good idea to have bare pointers to things lying around, but you insisted, and that's how you do it. That means you will have to remember to delete it at some point as well. And you will have to make sure that the copy construct of the class that holds the pointer does the right thing (and said right thing will be fairly complicated).
You have an interesting problem now. You are storing a multiset in each map entry. Fortunately this multiset will automatically be created and initialized to empty when a previously unknown key is accessed. OTOH, your use of bare pointers means that you have an exception safety problem. It's possible to leak memory if an exception is thrown anywhere along the way. So you have to catch any exceptions and clean up your object:
GraphObject *tmp = new GraphObject;
try {
(*the_Map)[key].insert(tmp);
} catch (...) {
delete tmp;
throw;
}
The fact your question is so basic makes me question your assertions about needing to use pointers. And I really wonder if you wouldn't rather have a multimap rather than a map from string -> multiset. But, you're adamant about the general form of your data structure. So the above is how you'd use it.
I'll also say that this data structure's copious use of bare pointers is a pretty bad idea. You'll have to write a pretty sophisticated functions to properly deconstruct or copy the whole mess.
Edit: sigh Coding at 4am on a data structure I would never create myself led me to write some very stupid code. The current version is much better. Though this answer is really much better than mine.
Why do I need to delete dynamically created items in vector, manually? Why wouldn't they get deleted or its destructor called when vector got deleted?
Normally something like this, but why needed ?
vector<int*> v;
for (vector<int*>::iterator it = v.begin(); it != v.end(); ++it)
{
delete *it;
}
Firstly, you store raw pointers in your vector. These pointers are just pointers. They can point anywhere. They can point to local objects, which cannot be deleted by delete. And even if they point to dynamically created objects, it doesn't necessarily mean that the user wants them to die with the vector. How is the vector supposed to know all this?
It is a matter of object ownership. Whoever owns the object is responsible for its proper and timely deletion. Ordinary raw pointers do not express ownership. That is why vector can't make any assumptions about whether the objects need to be deleted or not. If you want to tell the vector that it owns its dynamic objects, use corresponding smart pointers.
Secondly, note that your deletion technique is not necessarily safe in the general case. Some standard containers assume that the data you store in them is always valid. When you do delete on each vector element, the data in the vector becomes "invalidated" (pointers become indeterminate). This is OK with a vector. But doing something like this in a "smarter" container, like std::map or std::unordered_set for example, can and will lead to problems. Even if you destroy the container itself immediately afterwards, it is perfectly possible that the container's destruction algorithm might need to analyze (compare, hash etc.) the values of individual elements. And you just killed them all with your cycle.
Smart pointers naturally resolve this matter. But if you have to use a manual delete for raw pointers stored in a standard container, a better sequence of steps would be this
Retrieve the value of the element at i and store it in pointer p
Erase the element at i from the container
Do delete p
In the end you end up with an empty container and deleted data. Again, your approach will work for simple sequences, like std::vector or std::list, but don't do this with ordered or hashed ones.
Because the language has no way of knowing whether you need them to remain alive when you're done. What if you inserted some pointers to stack objects or something like that? Boom.
This, however, can be remedied by using a smart pointer, which will implement an appropriate policy as to automatic destruction. unique_ptr and shared_ptr are the most common and useful.
The destructor is not called because the pointer does not own the object to which it points.
In C++11, a std::unique_ptr<T> does indeed own the object to which it points. In this case, the destructor is called when the pointer is released, which is probably the behavior you want. (If you don't have a C++11 compiler but have a reasonably recent pre-C++11 compiler, unique_ptr is still available as part of TR1.)
The implementation of vector was just made to delete its memory only. Pointers do not have deconstructors. And in C++, there is no garbage collection or logic to see that it is pointers and recursive delete it.
If you would like to attend the next ISO meeting and propose that, be my guest, but for me, I just put it in an inline function:
template<class T>
public static inline void deleteVectorPointer(std::vector<T*> v)
{
for (vector<T*>::iterator i = v.begin(); i != v.end(); i++)
{
delete *i;
}
}
I've painfully learned during last few days a lot about programming in c++.
I love it :)
I know I should release memory - the golden "each malloc=free" or "each new=delete" rules exist now in my world, but I'm using them to rather simple objects.
What about vector ? Wherever I can, I'm using vector.clear() but that clearly isn't enough, because I'm having huge memory leaks.
Could you guide me on how should I treat this thing?
*Edit
Thanks, your comments made me think about the alghorithm of this application and I'll be able to eliminate the vector totally. :O
Sorry - I started explaining what is my use case here and I found out what I really need. It's like that when you code last 3 days for 18 hours a day :|
*Edit 2
This is crazy. By small changes in code, I've eliminated memory usage from 2x130 mb (constantly growing) into 2x 13,5mb, constant size. Thanks for making me think about that in another way.
Btw. such self code review got a name - anyone remember that? It's when you ask anyone (even your mother or dog) and start explaining what's your problem - and suddenly you solve this 5 hour problem yourself, just by trying to look at it from other point of view, or just by trying to summarize what's it all about. I often find myself being catched on that...
The rule is that when you clear a vector of objects, the destructor of each element will be called. On the other hand, if you have a vector of pointers, vector::clear() will not call delete on them, and you have to delete them yourself.
So if all you have is a vector of strings, and not pointers to strings, then your memory leaks must be caused by something else.
You don't need to be doing this. std::string cleans itself up, so the strings are not your problem. Remember that YOU didn't use new so YOU don't have to use delete.
You should probably learn about RAII - it makes allocation and deallocation much simpler. You'll avoid memory leaks this way.
Calling v.clear() will destroy all objects that are currently held inside v, but it will not release the memory (it is assumed that the vector will soon be filled again).
If you really want to free the memory, the idiom is
vector<string>().swap(v);
This will create a new (temporary) vector and swap its contents with v. The temporary vector is then destroyed, freeing the memory along with it.
Deleting elements from STL containers is guaranteed to call destructors on these elements.
However, if you have a container of some pointer-to-T type, then you still have to free the pointed-to memory yourself (in this case, the "destructor" for the pointer gets called, which is a no-operation).
If you do not want to manually manage memory in this case, consider using a smart-pointer solution or a pointer container.
The vector (like all standard containers) owns the objects inside it.
So it is responsible for destroying them.
Note: If you vector contains pointers then it owns the pointers (not what the pointers point at). So these need to be deleted. But there are easier ways.
You could use a vector of smart pointers. In fact you should be using some form of smart pointer for nearly everything. If you are using pointers you are probably still programming like a C programmer.
So:
std::vector<int> data; // clear is fine.
std::vector<int*> data1; // Now things need to be deleted.
// alternative 1:
std::vector<boost::shared_ptr<int> > data2; // The shared pointer will auto
// delete the pointer.
// alternative 2:
boost::ptr_vector<int> data3; // Here the container knows that
// it is holding pointers and will
// auto de-reference them when you
// its members.
But it sounds like you need to start thinking about learning about smart pointers.
int* x = new int(5);
// Do stuff.
*x = 8;
delete x;
// --- Instead use a smart pointer:
std::auto_ptr<int> x(new int(5));
// Do stuff.
*x = 8;
// No delete (the auto ptr handles it.
If you have a vector and it goes out of scope, all objects in the vector are destroyed. There isn't really a need to call clear() unless you want to dump the contents and reuse the vector.
However if you by any chance are using something like a vector then the destructor of the objects being pointed to will not be called as the vector destructor doesn't follow the indirections represented by the pointers.
All that said, have you actually confirmed that you've got genuine memory leaks and that they are caused by the data in the vector?
Give a use case. The destructor on the string is getting called by vector::clear. Your problem lies elsewhere my friend.
also check out:
Does std::vector.clear() do delete (free memory) on each element?
As rlbond suggested, use RAII.
It's a good rule of thumb to never put new and delete calls into your main code flow. Always try to put them into objects so that the object destructor can free what needs to be freed. In this way, you avoid needing to remember to call delete and it makes your code exception safe (assuming that you make your object's operations exception safe).
For example, if you had a vector of pointers to STL strings or C-style character arrays, put that into a StringContainer (use a better name) and have the StringContainer hold a vector and in the StringContainer destructor run a for loop to delete each string in the vector.
You can make the vector inside the StringContainer a public member and mess around with it directly, but it's even better design to make it private or protected and add some member functions to manage the string* vector.
So your main C++ program should never see a new or delete anywhere. Instead it should have a lot of stack allocated objects, auto_ptrs and shared_ptrs.