Is this the right way to write a destructor? - c++

Besides a lot of member functions, my Graph class has 3 main members: a vector of pointers to its vertices, called "vertex", a vector of pointers to its edges, called "edge", and an integer counter variable. I started/attempted to write the destructor to deallocate the memory from the vectors, but I'm not sure if I am doing it correctly. And what do I do about the counter? I tried to say "delete counter," but it's not a pointer (oops).
Graph<Object,Weight>::~Graph(){
for(unsigned int i=0; i<vertex.size(); ++i){
delete vertex[i]; }
for(unsigned int j=0; j<edge.size(); ++j){
delete edge[j]; }
//counter?
}

Deleting depends on the way you allocated, see The difference between delete and delete [] in C++
As for your int member, since you didn't dynamically allocate it (you didn't use new) you don't have to delete it.

Assuming the type of vertex is std::vector<Vertex*> and you create the vector as follows:
vertex.push_back( new Vertex );
your clean up code looks correct.
But, I urge you not to do this. Declare vertex as std::vector<std::unique_ptr<Vertex>> and you don't need to worry about deleteing the individual vector members anymore.
If you're using Boost, you could also make vertex a boost::ptr_vector.
As for the counter variable, unless you're newing the counter somewhere during class construction, you don't need to delete it.

is counter a plain ordinary int variable? If so, you're not in charge of its lifetime.
The delete keyword is only to be used when you've created an object with the new keyword. (And even then, only when there isn't something else in your program, such as shared_ptr which is doing the delete for you)
When using new/delete you're taking over from the language and managing the lifetime/existance of an object yourself. ordinary variables are created and destroyed automatically, meaning you don't need to worry about them.

You can delete an array of pointers with:
del[] arr; // arr is array of pointers.
Whereas, if counter is from stack, the program will take care of it, and you as programmer don't need to worry about freeing that memory.

I'm assuming that vertex and edge are allocated using new? then what you have written is fine but if you declared your vertex and edge as an array and newed using new [] operator then you need to use the delete [] call instead of delete, if the counter was not declared as a pointer and newed then there is no need to delete the counter.
As a design decision you should consider declaring your vertex and edge objects as boost::shared_ptr or unique_ptr so that they are reference counted and when the Graph object goes out of scope they are automatically cleaned up so you don't even need to flesh out your destructor.
If you have c++11 then you can use the std versions and not need boost like std::shared_ptr and std::unique_ptr.

Related

How to add pointers into a pointer to a vector

I have this:
std::vector<Pair *> *artistAttributes;
where Pair is a class, how can I add an element into this pointer?
I know how to access this if it was just a std::vector like so,
std::vector<Pair *> artistAttributes;
But I am unfamiliar with how to add elements into this since I am very new to pointers.
I am very knew to pointers.
There is a semantic difference between pointers that just point to objects on the automatic-storage ("stack") and pointers to objects on the free-store ("heap") in that pointers to objects on the heap must at some point be used to deallocate (delete/delete[]) the memory earlier allocated with new (or new[]).
This is not just easily forgotten but cannot be done when an exception is thrown between allocation and deallocation. To make that simpler, smart pointers were invented which follow the RAII/RDID-idiom ("Resource Acquisition Is Initialisation/Resource Destruction is Deletion"): Raw pointers are encapsulated in Objects that manage the lifetime of the resource they handle.
This makes it possible in many circumstances to avoid following the Rule of 3/5 (which is more a Rule of the Big Four (and a half) in modern C++) but use the Rule of Zero instead.
Also, there is no real point in having a pointer to a std::vector<> since vectors are cheap to copy (compared to the inconvenience of having to manage dynamically allocated memory).
So instead of
std::vector<Pair *> *artistAttributes;
better use
std::vector<std::shared_ptr<Pair>> artistAttributes;
Normally you access a member of an object with the . operator. If you wanna access the member of a pointer to an object you use the -> operator instead.
So you can modify the vector with artistAttributes->push_back() (to add a new element) or artistAttributes->at() (to modify an existing element). Equivalently you can also do (*artistAttributes).push_back() and (*artistAttributes).at().
See this:
std::vector<Pair*> *artistAttributes;
artistAttributes = new std::vector<Pair*>;
artistAttributes->push_back(new Pair())
...
for(int i=0; i<artistAttributes->size(); i++)
delete (*artistAttributes)[i] // Don't forget
delete artistAttributes; // Don't forget
In comparison to:
std::vector<Pair*> artistAttributes;
//artistAttributes = new std::vector<Pair*>; // no needed
artistAttributes.push_back(new Pair()) // use . instead of ->
...
for(int i=0; i<artistAttributes.size(); i++)
delete artistAttributes[i] // Don't forget
and in comparison to:
std::vector<Pair> artistAttributes;
//artistAttributes = new std::vector<Pair*>; // no needed
artistAttributes.push_back(Pair())

Memory deallocation inside a member function

I was thinking about a this situation not for a real implementation but to understand better how pointers works.
class foo(){
foo();
~foo();
void doComplexThings(const std::vector<int*>& v){
int* copy;
for(int i = 0; i < v.size(); i++){
copy = v[i];
// do some stuffs
}
}
}
main(){
std::vector<int*> myVector; // suppose we have 100 elements
doComplexThings(myVector);
for(int i = 0; i < myVector.size(); i++){
delete myVector[i];
}
myVector.clear();
}
Ok, I know that have no sense to copy v[i] inside an other pointer, but I was thinking: copy do a memory leak?
After the execution of doComplexThings(), copy will continue to exist and will occupy space in the heap?
After deleting all elements it will continue to exist and point to a deallocated memory?
So logically if I do this things with complex objects I'll keep occupy the memory with unreference object? Or copy is saved in the stack because I don't use new? And at the end of doComplexThings it will be deleted?
I'm a bit confused, thanks!
There is some confusion on the topic of pointers in the C++ community. While it is true that smart pointers have been added to the library to alleviate problems with dynamic memory allocation, raw pointers are not obsolete. In fact, whenever you want to inspect another object without owning it, you should use a reference or raw pointer, depending on which suits your needs. If the concept of ownership is unclear to you, think of an object as being owned by another object if the latter is responsible for cleaning up afterwards (deleting the former).
For example most uses of new and delete should be replaces with the following (omitting std for brevity):
{
auto ptr_to_T = make_unique<T>(//constructor params);
do_stuff_with_smart_ptr(ptr_to_T);
do_stuff_with_T(*ptr_to_T);
do_stuff_with_raw_ptr(ptr_to_T.get());
} // automatic release of memory allocated with make_unique()
Notice how a function that takes a T* doesn't need a smart pointer if it doesn't keep a copy of the T* it is given, because it doesn't affect the lifetime of the object. The object is guaranteed to be alive past the return point of do_stuff_with_T() and its function signature signals that it doesn't own the object by taking a raw pointer.
On the other hand, if you need to pass the pointer to an object that is allowed to keep the pointer and reference it later, it is unclear when the object will need to be destroyed and most importantly by whom. This is solved via a shared pointer.
ClassThatNeedsSharedOwnership shared_owner;
{
auto ptr_to_T = make_shared<T>(//constructor params);
shared_owner.set_T(ptr_to_T);
// do a lot of stuff
}
// At this point ptr_to_T is destroyed, but shared_owner might keep the object alive
So how does the above factor in to your code. First of all, if the vector is supposed to own (keep alive) the ints it points to, it needs to hold unique_ptr<int> or shared_ptr<int>. If it is just pointing to ints held by something else, and they are guaranteed to be alive until after the vector is destroyed, you are fine with int*. In this case, it should be evident that a delete is never necessary, because by definition your vector and the function working on the vector are not responsible for cleaning-up!
Finally, you can make your code more readable by changing the loop to this (C++11 which you've tagged in the post):
for (auto copy : v){
// equivalent to your i-indexed loop with copy = v[i];
// as long as you don't need the value of i
do_stuff_to_int_ptr(copy);
// no delete, we don't own the pointee
}
Again this is only true if some other object holds the ints and releases them, or they are on the stack but guaranteed to be alive for the whole lifetime of vector<int*> that points to them.
No additional memory is allocated on the heap when you do this:
copy = v[i];
variable copy points to the same address as v[i], but no additional array is allocated, so there would be no memory leak.
A better way of dealing with the situation is to avoid raw pointers in favor of C++ smart pointers or containers:
std::vector<std::vector<int>> myVector;
Now you can remove the deletion loop, which is an incorrect way of doing it for arrays allocated with new int[length] - it should use delete[] instead:
delete[] myVector[i];
Basically you're illustrating the problem with C pointers which lead to the introduction of C++ unique and shared pointers. If you pass a vector of allocated pointers to an opaque member function, you've no way of knowing whether that function hangs onto them or not, so you don't know whether to delete the pointer. In fact in your example you don't seem to, "copy" goes out of scope.
The real answer is that you should only seldom use allocated pointers in C++ at all. The stl vector will serve as a safer, easier to use version of malloc / new. Then you should pass them about as const & to prevent functions from changing them. If you do need an allocated pointer, make one unique_ptr() and then you know that the unique_ptr() is the "owner" of the memory.

destructing an object stored in the vector of pointers [duplicate]

This question already has answers here:
Does std::list::remove method call destructor of each removed element?
(6 answers)
Closed 9 years ago.
I have a class that contains pointers, the class inherits nothing
class MyClass
{
public:
MyClass();
~MyClass();
private:
//i have pointers here
};
MyClass::~MyClass()
{
print("destroyed..");
}
Now i have to use this class as a pointer in vector like this:
vector<MyClass*> classes;
Push some classes in here but when i remove an element:
classes.remove(index);
The destructor doesn't get called,and i think that I have a memory leak.
So how do i make it call the destructor
A vector of pointers does nothing to delete the pointers when they get removed or cleared from it. The vector cannot know if the pointers are dynamically allocated or not. It is not it's job to call delete.
It is up to you to call delete on the pointers, if and when it is necessary. There are not enough details in your question to determine whether it is necessary at all (you haven't shown how the objects pointed to are allocated). But since you claim there is a memory leak, this could indicate that they are dynamically allocated. The immediate solution is to call delete:
delete *it;
classes.erase(it); // vector has no remove member function
A safer solution is to store unique ownership smart pointers, such as std::unique_ptr<MyClass>. The standard library also provides smart pointers for shared and weak ownership. See Smart Pointers.
All the above is assuming that you do actually need to store a pointer. In general, it is safer and clearer to store values:
std::vector<MyClass> classes; // but don't call it "classes". A vector stores objects.
That's one of the reasons why you should avoid using std::vector<MyClass*> at first place. There's an ugly memory management connected with it and it won't stay as easy as classes.remove(index);
Basically, for every new a delete must be called and for every new[] a delete[] must be called, no matter whether you use this pointer as a local variable or you put it into the vector:
vector<MyClass*> vec;
vec.push_back(new MyClass()); // <-- object has been created
...
delete classes[index]; // <-- object shall be destructed
// the delete call will automatically invoke the destructor if needed
...
// now you can remove the dangling pointer from the vector
Just note that once the object has been destructed, any (old) reference to this object is invalid and trying to access this object using such reference (dangling pointer) will yield undefined behavior.
Firstly, std::vector has no remove, you probably mean erase.
Secondly, you need to manually call delete on whatever you're removing:
vector<MyClass*> classes;
auto iter = <iterator to index to remove>;
delete *iter;;
classes.erase(iter);
Or, to avoid all this pain, use a std::unique_ptr<MyClass>.
It is unclear who is responsible for managing the lifetime of the objects pointed by the pointers inside classes. Have you pushed newed pointers into it, or have you pushed the addresses of automatic storage objects?
If you have done the former, then you must manually delete the pointer before removing it. Else, if you have done the latter, then you could just leave it as is, just leaving the pointed-to objects destroy themselves as they leave their respective scopes. If you have mixed newed and non-newed pointers, whose possibility isn't that remote as you would think, then you're definitely damned, undefined behavior making demons fly out of your nose.
These kinds of situations involving pointers are very ambiguous, and it is generally recommended not to use pointers at all, and make the std::vector store plain objects, which makes your object lifetime management much simpler and the making the declaration just speak for itself.
vector<MyClass> classes; // Do this instead
You have to manually delete your pointers before your application exit or after your class object is removed from vector.
// Delete all
vector<MyClass*>::iterator it = classes.begin();
while (it != classes.end()) {
delete *it;
it = classes.erase(it);
}
Tip: Never add stack constructed pointers like following:
MyClass m;
classes.push_back(&m);
Edit: As suggested by other member the better solution is:
MyClass m(/* ... */);
vector<MyClass> classes;
classes.push_back(m);
However please note, you have to properly implement the copy constructor especially if your class has pointer data members that were created with new.
Make a temp pointer to hole MyClass* pointer before you remove it from your vector.
vector<MyClass*> classes;
//push some classes in here but
//when i remove an element
MyClass* temp = classes[index];
classes.remove(index);
// call delete temp; if you want to call the destructor thus avoid memory leak.
delete temp;
To avoid memory leak, remember never to loose control of heap object, always keep a a pointer or reference to it before object release.
It seems that you want your vector to be manager of your items.
Take a look at boost::ptr_vector class
its basically a wrapper around std::vector class.
You declare that this vector is the "holder" of these pointers, and if you remove them from this containers you want them to be deleted.
#include <boost/ptr_container/ptr_vector.hpp>
...
boost::ptr_vector<MyClass> myClassContainer;
myClassContainer.push_back(new MyClass());
myClassContainer.clear(); // will call delete on every stored object!

C++, vectors, pointers and objects confusion

I am working on a project as a homework for my university course of Systems Programming.
I got really confused with the matter of Pointers, Vectors, stacks and heaps.
Using C++.
I have to get a vector of objects which are courses, and those courses objects have several different fields.
What I did was this:
vector<CoursesObject> coursevector;
and then I created my Courses Object class, which contains the space left in course and name of course fields.
Now I want to add a new course, I do:
CoursesObject *theCourse = new CoursesObject(name, space);
now I want to add it to the handler vector:
coursevector.push_back(*theCourse);
With all I know, I created a vector of Courses objects on the stack, and made a new pointer to a new course that is on the heap, and added to the handler vector the pointer theCourse that points to the course object in the heap. Is what I said correct?
When I try to delete those course objects, I do:
for(int i=0; i<coursevector.size(); i++)
delete coursevector.at(i);
which gives me an error that it is not a pointer. But haven't I added to the coursevector a POINTER to the course object?
Please somebody explain, I have to handle the memory correctly and it seems that I am not getting it right.
This
vector<CoursesObject> coursevector;
is a vector of CourseObjects, so it cannot hold CourseObject pointers. When you do this:
coursevector.push_back(*theCourse);
you get a copy of the CoursesObject pointed at by theCourse stored in the vector. You do not need to delete any entries from the vector. In fact, you can't, because it doesn't hold pointers.
You program would be much simpler if you just avoided the dynamic allocation:
coursevector.push_back(CoursesObject(name, space));
You do not need to use new at all.
//This vector stores CoursesObject objects,
//not pointers to CoursesObjects.
vector<CoursesObject> coursevector;
//Construct theCourse with automatic storage
//duration.
CoursesObject theCourse(name, space);
//Copy theCourse into coursevector
coursevector.push_back(theCourse);
//theCourse will be automatically destroyed.
//coursevector (and all the objects that it contains)
//will be automatically destroyed.
all of your objects are not dynamically allocated, so you cannot delete them at any time during the program. Remember that you can only delete object once they are dynamically allocated:
int Var1 = 0; //cannot be deleted, scope and life will exist for the life of program
int * Var2 = new int; //CAN be deleted, dynamically allocated.
delete Var2; //free memory
You can however delete your last object, which is a pointer. I would grab the last element of the vector and call delete on it(which should be your pointer to the class).
when you do this:
coursevector.push_back(*theCourse);
actually you are dereferencing the pointer theCourse, so you are adding a copy of the object. You need to declare a vector of CourseObject pointers:
vector<CoursesObject *> coursevector;
Then you add an object:
coursevector.push_back(theCourse);
Now your code to delete the objects should work:
for(int i=0; i<coursevector.size(); i++)
delete coursevector.at(i);
coursevector can hold only CoursesObjects and not pointers to CoursesObjects, so you needn't use the new operator (check #Mankarse's answer). But, if you still want to hold pointers, then change the definition of coursevector to
vector<CoursesObject*> coursevector;
and push_back the value of the pointer as it is:
coursevector.push_back(theCourse);

boost::ptr_vector with arrays: Can I be sure that its destructor calls delete[] instead of delete?

I have the following case:
boost::ptr_vector<float> vec;
float* array = new float[4]();
vec.push_back(array);
// Add some more elements to vec..
How can I ensure that if I leave this scope and vec will be destroyed the ptr_vector's destructor calls delete[] and not delete on every element of vec. I don't understand how it should work, because the template parameter float will be the same for float* and float[4].
You could specify the CloneAllocator template parameter of ptr_vector to be something other than the default, heap_clone_allocator. There is no way to make an instance of the actual class boost::ptr_vector<float> use delete[] instead of delete.
For the arrays containint BUILT-IN simple type items (like float or char): i think there is no difference between delete and delete[], because delete[] assumes call many destructors - for each object of the array, but build-in primitive types doesn't assume calling destructor - there is nothing to destroy there; deallocating array of floats is just deallocating solid piece of memory without executing any code that might be placed in some kind of destructor. Murr...