I write a class vector
whose member is a dynamically allocated array
template <typename T> struct vector{
T* elem;int capacity;
/*
*capacity is the size of array, not number of elements in the array .
*the default capacity is 3.
*/
vector(int c=3,T e=0){ /* initializing all elements as e */
T* elem=new T[capacity = c];
for(int i=0;i<capacity;i ){
elem[i]=e;
}
}
~vector(){
delete[] elem;
}
};
Now this is the point, regarding the destructor of vector
. If the elements in the member elem
is also dynamically allocated object obj
, and this object also has its own destructor
int main(){
vector<obj*> vec;
vec.elem[0] = new obj(parameter)
vec.elem[1] = new obj(parameter)
vec.elem[2] = new obj(parameter)
...
}
Is it necessary to delete
all the objects in the destructor of vector
? like this
~vector(){
for(int i=0;i<capacity;i ){
delete elem[i];
}
delete[] elem;
}
Or I should only delete[] elem
and the destructor of obj
will finish the rest of work?
CodePudding user response:
Is it necessary to delete all the objects in the destructor of vector? like this
Technically yes but but what if you want a vector of pointers that does not represent ownership? You could easily end up either double-deleting an object, or trying to delete a stack-based object:
obj obj_a;
obj* obj_b = new obj;
vector<obj*> obj_ptrs;
obj_ptrs.elem[0] = &obj_a;
obj_ptrs.elem[1] = &obj_a;
obj_ptrs.elem[2] = obj_b;
delete obj_b;
Whether the pointed objects need to be deleted with the vector is none of the vector's business.
The cleanest way to address that is to use std::unique_ptr
, which is an object type that holds a pointer and deletes it when it gets destroyed:
#include <memory>
template <typename T> struct vector {
// ...
~vector() {
// The vector is only responsible for deleting the array.
delete[] elem;
}
};
// ...
void foo() {
vector<std::unique_ptr<obj>> obj_ptrs;
obj_ptrs.elem[0] = std::make_unique<obj>();
obj_ptrs.elem[1] = std::make_unique<obj>();
obj_ptrs.elem[2] = std::make_unique<obj>();
obj stack_obj;
vector<obj*> obj_no_own_ptrs;
obj_no_own_ptrs.elem[0] = obj_ptrs.elem[0].get();
obj_no_own_ptrs.elem[1] = obj_ptrs.elem[0].get();
obj_no_own_ptrs.elem[2] = &stack_obj;
// Everything gets deleted
// No double-delete concern
}
CodePudding user response:
In general, when you call delete in an object first it calls the destructor of the class, and second deallocate the memory where the object was allocated.
So, yes. If you create a class call vector it is necessary that you call delete if elem was dynamically allocated before with new.
New always have to be paired with delete. The standard approach was to, e.g. place the new in the constructor, and the delete in the destructor of a class.
In your case, in your class you are dynamically allocating space for other class, that happens to be also a dynamically allocated pointer.
first_object->second_object->third_object...
In this case first_object contain a dynamically allocated vector to second_object. second_object of course can contain more dynamically allocated memory.
In the destructor of your first_object, you delete the second_object so you call the destructor of the second object and deallocate its memory. The call to the destructor of the second_object should delete the third object, so its memory is also deallocated.
If you allocate memory and don't deallocate it, you start to mess the memory because you are fragmenting it. If you call delete without new, or in a object that has been already deleted there will be a segfault. It is always a good idea to place news in constructor and delete in destructors.
Nowadays you also can use shared_ptr or unique_ptr. They will automatically delete its content when they go out scope.
In particular shared_ptr will delete its content when the last pointer pointing to one resource goes out scope
Unique_ptr will delete its content when it goes out of scope, since by definition forbid more than one pointer pointing to its content.
{ std::shared_ptr foo = std::make_shared(); std::shared_ptr foo2(new Foo()); }
Both shared pointers will delete its content automatically when they will go out of scope. The first option is preferred and more efficient. You could also use unique_ptr that are similar in characteristics to shared_ptr they don't allow more than one pointer pointing to the same resource.
I think you can read about smart pointers and about RAII and it will help you with this