class Equipment
{
std::vector<Armor*> vEquip;
Weapon* mainWeapon;
int totalDefense;
int totalAttack;
public:
unsigned int GetWeight();
int * GetDefense();
bool EquipArmor(Armor* armor);
bool UnequipArmor(Armor* armor);
bool EquipWeapon(Weapon* wep);
bool UnequipWeapon(Weapon* wep);
Equipment();
virtual ~Equipment();
};
It seems like there should be no destructor. The vector of pointers will take care of itself when it goes out of scope, and the actual objects the pointers point to don't need to be deleted as there will be other references to it.
All of the objects in this refer to the main Container:
class Container
{
int weightLimit;
unsigned int currWeight;
std::vector<Item*> vItems;
public:
bool AddItem(Item* item);
bool RemoveItem(Item* item);
Container();
Container(int weightLim);
Container(int weightLim, std::vector<Item*> items);
~Container();
};
Now here I can see it being necessary to delete all objects in the container, because this is where all the objects are assigned via AddItem(new Item("Blah"))
(Armor and Weapon inherit from Item)
Non-pointer types will take care of themselves. So, ints, floats, objects, etc. will take care of themselves, and you don't have to worry about deleting them.
Any pointers that are managed by the class need to be deleted by that class' destructor. So, if the memory pointed to by the pointer was allocated in the class or if it was given to that class with the idea that that class would manage it, then the destructor needs to delete the pointer.
If the pointer is to memory that another class is managing, then you obviously don't want your destructor to delete it. That's the job of the class that is in charge of the memory pointed to by that pointer.
Standard containers do not manage the pointers that they hold if they hold pointers. So, if you have a container of pointers, whichever class is supposed to manage them needs to delete them. Odds are that that's the class that holds the container, but that depends on what your code is doing.
So, typically, for a class that has a container of pointers, you'll need something like this in the destructor:
for(containerType<T*>::iterator iter = container.begin(),
end = container.end();
iter != end;
++iter)
{
delete *iter;
}
Every pointer that has memory allocated to it has to have something (generally a class, but sometimes the function that it's allocated in) who effectively owns that memory and makes sure that it is freed. When talking about classes, that's usually the same class that the memory is allocated in, but of course, it's quite possible for one class or function to allocate the memory and then effectively pass on the ownership of that memory to another class or function. Regardless, whoever "owns" the memory needs to deal with cleaning it up. That's what your destructor needs to worry about: cleaning up any resources that that class owns.
If you need to delete the items, then:
Container :: ~Container() {
for ( unsigned int i = 0; i < vItems.size(); ++i ) {
delete vItems[i];
}
}
Note that for this to work correctly, the Item class must have a virtual destructor, if the array really contains pointer to Armour and Weapon instances.
If I understand you correctly, you're asking how to delete items from the vItems vector in the main container destructor?
for(std::vector<Item*>::iterator i=vItems.begin(),ie=vItems.end();i!=ie;++i)
delete *i;
Is that what you are asking for?
If your vector would be
std::vector<std::tr1::shared_ptr<Item> >
, then you wouldn't need a destructor. As it is now, the destructor would have to iterate over the vector to delete all items. Easiest with BOOST_FOREACH.
It depends on how you implement it. If the items you add are managed from outside your object (i.e. the body of addItem() looks something like this: { vItems.push_back(items); }), then you won't need a destructor for that one. However, if the items are managed by the object (i.e. addItem() looks like this: { vItems.push_back(new Item(item)); }, then you will need to delete all items in the destructor, because nobody will do that for you.
Related
In my class I wrote
class Game {
private:
mtm::Dimensions dimensions;
std::vector<Character*> board;
public:
explicit Game(int height, int width):dimensions(height,width), board(height*width){
}
~Game() {}
};
But how should I free my vector, I think it leaks memory if I leave the d'tor empty.
If Game is not the owner it must not free the memory. The owner has to clean up.
If Game is the owner it can delete all elements in the destructor
~Game() {
for (auto &character : board) {
delete character;
}
}
The better way is to use smart pointers and remove the destructor
std::vector<std::unique_ptr<Character>> board;
You should try to follow the rule of 0
Assuming that your Game owns the objects, then your Game destructor would need to free up the memory. Presumably, the Characters are allocated with new. The below will delete all the Characters in the board, then the class variables (like the vector) will automatically be freed afterward.
~Game() {
for ( Character *character : board )
delete character;
}
Unless this is for an exercise with pointers, it's generally recommended not to use bare-pointers, and instead use a smart pointer, such as unique_ptr or shared_ptr.
std::vector<std::shared_ptr<Character>> board;
In this case, there will be no leak, since the Characters will automatically be freed once no one points to them anymore.
Use of shared_ptr vs unique_ptr is dependent on what you're doing.
The vector is a member variable. Member variables, like all sub objects are automatically destroyed when the super object is destroyed. The implicitly generated destructor does the right thing for vector.
Note that the vector contains pointers. If those pointers point to dynamically allocated objects, and are the only pointers to those objects, then those objects would have to be deleted, or else they would leak. If something else owns the pointed objects, then there is nothing that needs to be done in this destructor.
An example where the implicit destructor is correct. I pretend that the member is public for this example:
{
Character c;
Game g;
g.board.push_back(&c);
} // no leaks
Avoid owning bare pointers. Prefer to use RAII containers or smart pointers if you need ownership of dynamic objects.
the vector destructor won't leak memory you should write destructors for the types used in the vector. Also I wouldn't recommend a pointer to something which dosen't destruct itself.
I think what you are looking for are smart pointers.
I know it's basic question but I'm quite new to C++ and I'd like to know if for example I have 2 classes:
class MyClass1 {
private:
vector<int> iVals;
std::string name;
public:
MyClass1(std::string name) {
this->name = name;
}
~MyClass1() {
//empty
}
};
class MyClass2 {
private:
vector<int>* iVals;
std::string* name;
public:
MyClass2(std::string name) {
this->iVals = new vector<int>();
this->name = new std::string(name);
}
~MyClass2() {
delete this->iVals;
delete this->name;
}
};
Instances of both classes I can initialize statically or dynamically in main() method
int main() {
MyClass1 c_1("one");
MyClass1* c_11 = new MyClass1("one one");
MyClass2 c_2("two");
MyClass2* c_22 = new MyClass2("two two");
}
My question is what is better way to implement such classes? With "static"(no the static keyword) or dynamic fields?
If I do
MyClass1* c_11 = new MyClass1("one one");
If I'm correct, objects fields, which are not allocated dynamically, will be allocated also on heap. So is there any practical reason to allocate any class member dynamically?
While there is sometimes a use for dynamically allocated members (I basically use them for polymorphic members and that's about it), I would not use it like you implemented MyClass2. This has many possibilities for bugs, the foremost (in my opinion) beeing:
You did not define a copy/move constructor and copy/move assignment. The implicit constructors would only work on the value of the pointer and not the object it's pointing to. So if you have MyClass2 a("Hi"); MyClass2 b = a; both of them would point to the same std::string. If one goes out of scope, this object is deleted and the other pointer is dangling. Hence, we have the so called rule of five.
Hence, if you have an object owning memory, you should use std::unique_ptr. It is a wrapper around a pointer, which deletes it if the object is deleted. Due to this the default constructors and deleter work perfectly well and you dont have to worry at all about managing the memory. All of this comes with minor runtime overhead.
If you come to the point, where multiple objects share some memory and you cannot say that one of those outlives all others, working with raw pointers becomes very troublesome. Then you should look at std::shared_ptr. But be careful, it is easy to get a hefty overhead if not used in the right way.
It is ok to use raw pointers if you just want to look at an object or modify it and are absolutely sure that the object pointed to will not get deleted while doing so. But having raw new and delete in your code should always make you think whether it is really needed.
Does the delete() operator destroy all the sub-objects of an object too?
Or do I need to call the delete of sub-object before deleting the parent object?
class equipment
{
public:
int model_id;
...
}
class player
{
public:
int x, y;
equipment * Equipment;
player(void) { Equipment = new equipment[2];};
~player(void) { delete [] Equipment; }
};
int main (....)
{
player = new Player;
...
...
delete Player;
}
you need to delete the dynamically allocated subobjects in the destructor of the main object and you have properly done this by deleting array Equipment
Delete operator does delete all "subobjects" as you say, but usually and in your case you need to delete not only "sub objects" but also memory, where member pointers point to.
So if you used vector object, for example, it would be deleted automatically, but in this case you need to delete it explicitly, which you did correctly
To put it simply, during destruction of the object :
Member objects are themselves destroyed
Objects pointed by member pointers aren't
That means that you have to delete them manually (like your Equipement pointer), if you own them. There might be case when your class ends up with a pointer it does not own (for example, a handle to some other object you need in this class), and thus should not delete.
You can use smart pointers (i.e.:std::shared_ptr, std::unique_ptr, etc.) to manage memory in a safer way (they, notably, automatically delete the pointers they manage, following the RAII principle ).
One thing you are missing is the destructor in class equipment
The stuff you do in your example is sufficient, you
delete[] Equipment;
in the destructor of player, so all contained equipments will be deleted as soon as a player gets deleted.
Nicely done!
I have had a good look at some other questions on this topic and none of them (to my knowledge) address how to correctly erase items from a stl list of objects which contain dynamicically assigned memory vs. a stl list of objects that don't contain dynamically assigned memory.
I want to use a list of objects. Take this object for example (which contains no dynamically assigned memory):
class MyPoint {
public:
MyPoint(int _x,int _y)
{
x = _x;
y = _y;
}
private:
int x;
int y;
};
So I might create a list of objects (not pointers to them), add things to it and then erase an element:
list<MyPoint> myList;
myList.push_back(MyPoint(3,4));
myList.push_back(MyPoint(1,2));
myList.push_back(MyPoint(8,8));
myList.push_back(MyPoint(-1,2));
list<MyPoint>::iterator it;
it = myList.begin();
advance(it,2);
myList.erase(it);
My list now contains:
(3, 4)
(1, 2)
(-1, 2)
QUESTION 1a: do I need to do anything else to the erased object or will the memory be taken care of?
QUESTION 1b: if the program ends, do I need to do something with the remaining objects in the list? Do I need to delete them all and deal with their memory somehow?
Ok, now consider an alternative version of the class that allowed a point in N-dimensional space. I.e., I could dynamically assign an array of length N to hold the N points inside the class (I have spared you the implementation as that is not in question here). The destructor of the class would then delete the dynamically assigned array using 'delete'.
class MyDynamicPoint {
public:
MyDynamicPoint(int N)
{
points = new int[N];
}
~MyDynamicPoint()
{
delete points;
points = NULL;
}
private:
int *points;
};
I might now create a list of pointers to the objects, instead of the objects themselves:
list<MyDynamicPoint*> myList;
myList.push_back(new MyDynamicPoint(8));
myList.push_back(new MyDynamicPoint(10));
myList.push_back(new MyDynamicPoint(2));
myList.push_back(new MyDynamicPoint(50));
list<MyDynamicPoint*>::iterator it;
it = myList.begin();
advance(it,2);
myList.erase(it);
QUESTION 2a - Is the above correct? I.e. Because this new version of the class would contain some dynamically assigned memory, does this mean I have to create a list of pointers to objects, not the objects themselves?
QUESTION 2b - Given that I have just erased the pointer from the list, where do I call delete to deal with the fact there is now dynamic memory to be deleted in the objects? Or does the erase method of stl list call the destructor of the object, taking care of it?
Many thanks in advance for any help,
Best,
Adam
When you have a class with data members that have automatic storage duration (i.e. their lifetime is tied to the instance of this class) like this:
class MyPoint {
private:
int x;
int y;
};
and you will use list<MyPoint> myList;, then this instance of std::list is also an object with automatic storage duration, that will be cleaned up automatically and by the time the container is destructed, so are the elements it holds. Everything is taken care of.
But the latter version is not very lucky choice... not only that you have a container holding pointers, you even decided to create a data member of class Point that will be allocated dynamically. At first note that everything that has been allocated by calling new should be freed by calling delete and everything allocating by calling new[] should be freed by calling delete[].
In this situation, you are allocating the memory when the object is constructed and cleaning it up when the object is destructed:
MyDynamicPoint(int N)
{
points = new int[N];
}
~MyDynamicPoint()
{
delete[] points;
points = NULL;
}
private:
int *points;
You would achieve the same by using some std::vector or std::array instead of the C-style array and you wouldn't have to take care of the memory management on your own:
MyDynamicPoint(int N) : points(std::vector<int>(N, 0)) { }
private:
std::vector<int> points;
the std::vector object will take care of memory management for you.
And last thing: when you dynamically allocate an element and store it into the container:
myList.push_back(new MyDynamicPoint(8));
you need to free this memory on your own, erasing the pointer from the list is not enough:
list<MyDynamicPoint*>::iterator it;
...
delete *it;
myList.erase(it);
So whatever you want to achieve, always prefer objects with automatic storage duration if the situation allows it. There's nothing worse than being forced to taking care of memory management manually and dealing with unpleasant problems such as memory leaks later.
QUESTION 1a: do I need to do anything else to the erased object or will the memory be taken care of?
You don't need to do anything.
QUESTION 1b: if the program ends, do I need to do something with the remaining objects in the list? Do I need to delete them all and deal with their memory somehow?
You don't need to do anything.
QUESTION 2a - Is the above correct?
The code is not correct. You're violating The Rule of Three. In particular, the automatically-generated MyDynamicPoint's copy constructor and assignment operator will make a bitwise copy of the points pointer. If you copy an instance of MyDynamicPoint, you'll end up with two object sharing the same points pointer:
When one of the objects goes of scope, the other becomes unusable.
When the second object goes out of scope, its destructor will attempt to free memory that's already been freed. This is undefined behaviour.
I.e. Because this new version of the class would contain some dynamically assigned memory, does this mean I have to create a list of pointers to objects, not the objects themselves?
No, it does not mean that. In fact, you should probably continue to store objects by value. However, you do need to fix the rule of three.
QUESTION 2b - Given that I have just erased the pointer from the list, where do I call delete to deal with the fact there is now dynamic memory to be deleted in the objects? Or does the erase method of stl list call the destructor of the object, taking care of it?
Since you have a list of raw pointers, the destructors will not be called automatically. The easiest way to fix that is to either store objects by value, or use std::unique_ptr or std::shared_ptr instead of raw pointers.
To question 1, there is nothing you need to do. As you store the objects by value the compiler and the library will handle everything.
However, when you store pointer as in the second case, you need to delete those pointers that you have allocated with new, or you will have a memory leak.
And you have to delete the pointers before doing the erasing, as that can invalidate the iterator:
delete *it;
myList.erase(it);
I think following should work
MyPoint* ptr = myList.back();
delete ptr;
myList.pop_back();
OR
MyPoint* ptr = myList.back();
delete ptr;
myList.erase(ptr);
Suppose I have a class similar to the following:
#include <vector>
class element
{
public:
element();
~element();
virtual void my_func();
private:
std::vector<element*> _elements;
};
How would I go about implementing the destructor?
I was thinking something like this, but I'm not sure. I am worried about memory leaks since I'm relatively new to C++.
void element::destroy()
{
for(int i = 0; i < _elements.size(); ++i)
_elements.at(i)->destroy();
if(this != NULL)
delete this;
}
element::~element()
{
destroy();
}
Thank you.
PS:
Here is a sample main:
int main()
{
element* el_1 = new element();
element* el_2 = new element();
element* el_3 = new element();
el_1.add_element(el_2);
el_2.add_element(el_3);
return 0;
}
Also, what if I do this (aka don't use new):
int main()
{
element el_1;
element el_2;
element el_3;
el_1.add_element(&el_2);
el_2.add_element(&el_3);
return 0;
}
element::~element()
{
typedef std::vector<element*>::const_iterator iterator;
for (iterator it(_elements.begin()); it != _elements.end(); ++it)
delete *it;
}
delete this in a destructor is always wrong: this is already being destroyed!
In addition, you would need to declare a copy constructor and copy assignment operator (either leaving them undefined, making your class noncopyable, or providing a suitable definition that copies the tree).
Alternatively (and preferably), you should use a container of smart pointers for _elements. E.g.,
std::vector<std::unique_ptr<element>> _elements;
When an element is destroyed, its _elements container will be automatically destroyed. When the container is destroyed, it will destroy each of its elements. A std::unique_ptr owns the object to which it points, and when the std::unique_ptr is destroyed, it will destroy the element to which it points.
By using std::vector<std::unique_ptr<element>> here, you don't need to provide your own destructor, because all of this built-in functionality takes care of the cleanup for you.
If you want to be able to copy an element tree, you'll still need to provide your own copy constructor and copy assignment operator that clone the tree. However, if you don't need the tree to be copyable, you don't need to declare the copy operations like you do if you manage the memory yourself: the std::unique_ptr container is itself not copyable, so its presence as a member variable will suppress the implicitly generated copy operations.
class element
{
public:
element();
~element();
private:
std::vector<element*> _elements;
};
Per the Rule of Three, this lacks the definition of copy constructor and assignment operator.
element::~element()
{
destroy();
}
Calling delete this (which is what destroy() does) from a destructor is always wrong, because the destructor is what is called when the current object is being deleted.
for(int i = 0; i < _elements.size(); ++i)
_elements.at(i)->destroy();
While this does the job of calling delete on the objects you call destroy() for, this arrangement has the disadvantage that you must not destroy such objects other than through calling destroy(). In particular, this
element el_1;
will be a problem, because e1_1 will be automatically destroyed when it falls out of scope bay calling its destructor. Since this calls destroy(), which invokes delete this on an object not allocated using new, this causes Undefined Behavior. (If you are lucky it blows up into your face right away.)
It would be far better to remove the delete this from the destructor, and only have the destructor delete the objects in the object's vector:
for(std::vector<element*>::size_type i = 0; i < _elements.size(); ++i)
delete _elements[i];
if(this != NULL)
delete this;
Checking a pointer for NULLness is never necessary, because delete is defined to do nothing when the pointer passed to it is NULL.
The delete this shouldn't be there, as the object is already under destruction by definition.
If you copy an element then all the pointers within its member vector are copied too; then when the original goes out of scope their pointees are destroyed, and the element copy has a vector of dangling pointers. You need a copy ctor and assignment operator.
So, just this basic start has already created two very serious faults. This is a sign that the design is to be avoided. It doesn't appear to be all that clear what the ownership semantics are to the programmer who uses it.
Why is dynamic allocation required here at all? Why not store elements objects themselves?
#include <vector>
class element
{
public:
void add_element(element const& e) {
_elements.push_back(e);
}
private:
std::vector<element> _elements;
};
This will change your program subtly if you previously had multiple references to the same element going into different other elements, but you'll have to decide for yourself whether that tangled mess of dependencies is something you need.
Nope, it doesn't work that way. You never delete this. You just don't. Basically, take out your destroy method, put everything into ~element() except for the delete this part. And instead of calling the destroy method, just delete _elements[i];.