0

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?

5
  • Just put a breakpoint or some debug output into the destructor and observe what happens. On a related note, does your C++ tutorial contain a rule about pairing of new and delete? Commented Nov 1, 2021 at 13:22
  • 3
    Use vector<std::unique_ptr<obj>> Commented Nov 1, 2021 at 13:23
  • 2
    And if you can't use the standard library (for some reason), make your own unique_ptr to go alongside your vector. You should NEVER have a vector of owning raw pointers. Commented Nov 1, 2021 at 13:25
  • Simple rule: everything you new you also need to delete. Unless something else does it for you. Commented Nov 1, 2021 at 14:10
  • I am a beginner for C++. I write my own vector because of the request of Data Structure course I am joining. The use of STL is forbidden. And that's true that I believe I should pair new and delete, is it wrong? Thanks, I will try to debug to see the result :D Commented Nov 1, 2021 at 14:12

2 Answers 2

2

Is it necessary to delete all the objects in the destructor of vector? like this

Technically yes 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
}
Sign up to request clarification or add additional context in comments.

2 Comments

Thank you(although I don't got it because I never learned STL hahaha :D). I am convinced that great challenge for learning C++ still remain. (Life is short, I want to use Python QAQ)
@YoRHa Learning how to use std::vector and std::unique_ptr would take you a lot less time than writing equivalents by hand. Just sayin'.
0

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.

  1. In particular shared_ptr will delete its content when the last pointer pointing to one resource goes out scope

  2. 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 (make_shared better than call the constructor with new). 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

4 Comments

shared_ptr are "convenient" because they are copyable, but they come with some severe drawbacks. Convenience is not a good enough reason to use them. They should be used only when strictly necessary,
shared_ptr is definitely not more efficient than unique_ptr. In fact, the opposite is true. For instance, shared_ptr uses type erasure for deleters and has significant runtime and memory overhead.
Not to mention that their atomicity can mess with code reordering, preventing optimizations.
@DanielLangr I think I explained myself bad, I intended to say that std::make_shared is more efficient than call the constructor, I will rewrite it now, my mistake for English not being my other tongue

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.