2

According to answers in this question : "How does delete[] "know" the size of the operand array?"

your allocator will keep track of how much memory you have allocated

and

How free knows how much memory to deallocate"

Yes, the memory block size is stored "somewhere" by malloc (normally in the block itself), so that's how free knows. However, new[]/delete[] is a different story. The latter basically work on top of malloc/free. new[] also stores the number of elements it created in the memory block (independently of malloc), so that later delete[] can retrieve and use that number to call the proper number of destructors

Does this mean that delete[] is independent on where the pointer points to? Is the following code valid or will it result in memory leaks?

void createArray(){
    char* someArray = new char[20];
    readData(someArray);
    //Is this delete still valid after moving the pointer one position?
    delete[] someArray;
}

char readData(char* &arr){
    char value = *arr;
    //Let it point to the next element
    arr += 1;
    return value;
}
Kilian
  • 1,540
  • 16
  • 28
  • 1
    Your example does not do what you think it does, you meant to write `char readData(char*& arr) {...` –  Jan 18 '18 at 13:39
  • 4
    `readData` gets a **copy** of the pointer; the increment changes the copy, but does not affect the original value. Regardless, `operator delete[]` must be called with a value that was returned by `operator new[]`. – Pete Becker Jan 18 '18 at 13:40
  • @PeteBecker Now it gets a reference! (OP edited) – peterchen Jan 18 '18 at 13:51

3 Answers3

8

Yes it does. If you change a new[]-ed pointer value and then call delete[] operator on it you are invoking undefined behavior:

char* someArray = new char[20];
someArray++;
delete[] someArray; // undefined behavior

Instead store the original value in a different pointer and call delete[] on it:

char* someArray = new char[20];
char* originalPointer = someArray;
someArray++; // changes the value but the originalPointer value remains the same
delete[] originalPointer; // OK
Colin
  • 3,394
  • 1
  • 21
  • 29
Ron
  • 14,674
  • 4
  • 34
  • 47
  • Just for sake of totally understanding. after line `char* originalPointer = someArray;` both pointers are equal. I may also alter originalPointer++ and follow up with delete[] on someArray. Is this correct? – Kilian Jan 18 '18 at 13:58
  • 1
    After that line - both pointers are equal. You might not call `delete[]` on changed `originalPointer++`. Don't change the value of the `originalPointer` as we need it to point at the originally allocated memory region. The value of `someArray` can be changed as we will not be calling operator `delete[]` on it. – Ron Jan 18 '18 at 14:09
1

You might be interested to know what new and delete really do under the covers (some licence taken, ignores exceptions and alignment):

template<class Thing>
Thing* new_array_of_things(std::size_t N)
{
  std::size_t size = (sizeof(Thing) * N) + sizeof(std::size_t);
  void* p = std::malloc(size);
  auto store_p = reinterpret_cast<std::size_t*>(p);
  *store_p = N;
  auto first = reinterpret_cast<Thing*>(store_p + 1);
  auto last = first + N;
  for (auto i = first ; i != last; ++i)
  {
    new (i) Thing ();
  }
  return first;  
}

template<class T>
void delete_array_of_things(Thing* first)
{
    if (first)
    {
        auto store_p = reinterpret_cast<std::size_t*>(first) - 1;
        auto N = *store_p;
        while (N--)
        {
            (first + N)->~Thing();
        }
        std::free(store_p);
    }
}

Summary:

The pointer you are given is not a pointer to the beginning of the allocated memory. The size of the array is stored just before the memory that provides storage for the array of objects (glossing over some details).

delete[] understands this and expects you to offer the pointer that was returned by new[], or a copy of it.

Richard Hodges
  • 68,278
  • 7
  • 90
  • 142
  • According to: https://stackoverflow.com/a/47771835/2393593 you can use delete[] on pointer that was not original. You don't need to "offer the very same pointer" according to the linked answer. What did you mean by saying that? I got confused because of that. You are talking about "the very same pointer" as it shouldn't have been moved forward in address? – Morfidon Oct 24 '19 at 06:10
  • @Morfidon perhaps I should say the same pointer or a copy of it. – Richard Hodges Oct 24 '19 at 16:06
0

General rule is that you can delete only pointers you got from new. In an non-array version you are allowed to pass a pointer to base class subobject created with new (granted the base class has virtual destructor). In case of array version, it must be the same pointer.

From cppreference

For the second (array) form, expression must be a null pointer value or a pointer value previously obtained by an array form of new-expression. If expression is anything else, including if it's a pointer obtained by the non-array form of new-expression, the behavior is undefined.

Tadeusz Kopec for Ukraine
  • 12,283
  • 6
  • 56
  • 83