3

I was implementing classes my_unique_ptr and my_shared_ptr that mimic the standard library smart pointers std::unique_ptr and std::shared_ptr to get to know it better.

When implementing the destructors I'm in this trouble to decide whether to use delete or delete[] to free the memory. As much as I read on SO and other sites, there is no portable way to know how many bytes were allotted by new[] (or whether new was used or new[]) (How many bytes were allocated by new?)

While implementing class my_unique_ptr I have no way of knowing how many bytes the user will request from the constructor , i.e.

Whether he will do my_unique_ptr<int> ptr1(new int)

or will he do my_unique_ptr<int> ptr1(new int[5])

If there is a way please let me know!

Here is my class (simplified and without cpy/move constructors):

template<typename ValueType>
class my_unique_ptr {

    ValueType *internal_ptr = nullptr;

public:
    
    // Default constructor
    my_unique_ptr() {
       internal_ptr = nullptr;
    }

    // Paramterized constructor
    explicit my_unique_ptr(ValueType *ptr) {
       if (ptr)
        internal_ptr = ptr;
    }

    // Destructor
    ~my_unique_ptr() {
       
        // How do I know whether to use
           delete ptr;

        // or
           delete[] ptr;
        
     }

I read somewhere that the compiler keeps track of the argument of new[] which is then used by delete[] to free the memory correctly. Also read that "It is the responsibility of the programmer to match new with delete and new[] with delete[]". But how do I program this in my class so that it always matches the correct operators?

Sidenote:

Running valgrind while using delete everywhere instead of delete[] and passing more than 1 int (say with new int[5]) in my constructor, Valgrind says that all memory blocks were freed and there is no chance of leak! (although shows warnings like mismatched new[] with delete. Does this mean delete is successfully freeing all the 5 ints allocated by new[]? Please help. I'm on Ubuntu 18.04 and using gcc 7.5.0.

Siraj Qazi
  • 33
  • 3

2 Answers2

2

You are correct that you can't know if a memory was allocated by new or new[]. But you can't even know that a memory stores an automatic duration object. E.g. your user can do:

int a = 24;

my_unique_ptr<int> ptr1(&a); // oups

There is no way for you to know that. So do what the standard library does:

  • make a specialization for array types, e.g. template <class T> class my_unique_ptr<T[]> that calls delete[] on the destructor.

  • It is a requirement that my_unique_ptr<T> must be initialized with a memory obtained from new and my_unique_ptr<T[]> must be initialized with a memory obtained from new[]. This is a contract the users of your library must respect. If it's not respected then it's UB.

  • help the users respect this contract by providing equivalents of std::make_unique. Also see Advantages of using std::make_unique over new operator


Does this mean delete is successfully freeing all the 5 ints allocated by new[]

No. Calling delete on a memory not obtained from new is UB.

bolov
  • 58,757
  • 13
  • 108
  • 182
  • I understand. Thank you so much for clearing this! I guess I didn't think of the possibility of another template specialization with `` and so I wasn't getting how the compiler could possibly get the operators correctly matched. Thank you so much again :) – Siraj Qazi Jun 24 '20 at 04:58
0

Actually, standard library smart pointers have extra facility than your code that they are able to take what operator(delete or delete[]) to use when their destructor is called. They take delete by default, and if you want to use delete[], you should provide it to the smart pointer constructor. Other than that, if you create a single object, use new and delete. if you create an array, use new[] for it, and delete[] for deleting it.

K.R.Park
  • 174
  • 9
  • 4
    You don't have to use a custom deleter at all, just use e.g. `std::unique_ptr`. There is a specialization for `T[]` that uses `delete[]`. – cdhowie Jun 24 '20 at 04:49
  • @cdhowie I was completely unaware of this kind of solution. A good point to learn. Thank you. – K.R.Park Jun 24 '20 at 04:58
  • Yes thats all fine I get all that but I can't know whether the user is gonna create a single object or an array and that was what I asked. Anyway I got my answer from @bolov and cdhowie – Siraj Qazi Jun 24 '20 at 05:07