4

How to delete an array declared with new if I don't have access to the original pointer x? Let's assume, I know the array size.

For example, if I write the following code:

void enlarge(int * x) {
    int * tmp = new int[20];
    memcpy(tmp, x, 10*sizeof(int));
    delete[] x; //?
    x = tmp;
}

int main() {
    int * x = new int[10];
    enlarge(x);
    delete[] x; //??? free(): double free detected in tcache 2
}
  1. Would delete[] within enlarge() function know how much memory to free?
  2. Apparently, delete[] within main() results in an error during execution. Why? How to avoid it?
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
user1079505
  • 173
  • 1
  • 8
  • 1
    `enlarge` should probably return a new pointer, and then can be called as `x = enlarge(x)`. Otherwise, you are deleting old memory and leaking new. The caller can no longer access either. Better still, do yourself a favor and use `std::vector` – Igor Tandetnik May 07 '23 at 21:28
  • Yes, it does. Preferrably you'd leave freeing the data to a smart pointer though: `void enlarge(std::unique_ptr & x) { auto tmp = std::make_unique(20); memcpy(tmp.get(), x, 10 * sizeof(int)); x = std::move(tmp); }` `int main() {auto x = std::make_unique(10); enlarge(x);}` – fabian May 07 '23 at 21:28
  • 3
    ***Apparently, delete[] within main() results in an error during execution. Why? How to avoid it?*** Because you pass `x` by value. `void enlarge(int * x) {` copies x and enlarges it freeing the original memory location but not changing `x` in main which after running enlarge `x` in `int main()` points to the original location which you attempt to free a second time in `int main()` – drescherjm May 07 '23 at 21:29
  • 5
    Incidentally, the concept of array decay is irrelevant here. It doesn’t happen in your code anyway: all variables you declare of *pointer*, not array, type. – Konrad Rudolph May 07 '23 at 21:34
  • @KonradRudolph Do you mean that _array decay_ refers only to arrays declared statically, e.g. with `int x[10]`? – user1079505 May 07 '23 at 21:48
  • 1
    @user1079505 *"Do you mean that* array decay *refers only to arrays declared statically, e.g. with `int x[10]`?"* -- Inaccurate. Array decay occurs only when you have an object whose type is an array. If you declare `int x[10]` then the type of `x` is an array. If you declare `int * x` then the type of `x` is a pointer. A pointer cannot be subject to the decay **from an array to a pointer** because 1) a pointer is not an array and 2) a pointer is already a pointer. – JaMiT May 07 '23 at 22:42

3 Answers3

2

The function enlarge produces a memory leak because the pointer x declared in main is passed to the function by value. That is the function deals with a copy of the value of the original pointer x. Changing within the function the copy leaves the original pointer x declared in main unchanged.

As a result this statement in main

delete[] x;

invokes undefined behavior because the memory pointed to by the pointer x was already freed in the function enlarge.

You need to pass the pointer by reference like

void enlarge(int * &x) {
    int * tmp = new int[20];
    memcpy(tmp, x, 10*sizeof(int));
    delete[] x;
    x = tmp;
}

Pay attention to that instead of raw pointers it is better to use standard container std::vector.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
2

How to delete an array declared with new if I don't have access to the original pointer x?

You cannot. In order to delete a dynamic array, you must know the pointer to the first element of that array - i.e. the pointer that was returned by new.

Would delete[] within enlarge() function know how much memory to free?

Yes.

Apparently, delete[] within main() results in an error during execution. Why?

Because the same pointer was already deleted in enlarge. If you delete a pointer more than once, the behaviour of the program is undefined.

How to avoid it?

Don't delete a pointer more than once.

P.S. enlarge leaks the array that it allocates. Don't use new and delete. Use RAII containers such as std::vector instead.


Ah, so array decay affects only statically declared arrays

Array decay is an implicit conversion of an expression of array type to a pointer to first element. The type of x is int*. That is not an array type. int* is a pointer type. As it isn't an array type, it doesn't implicitly convert to a pointer to first element. x is already the pointer to the first element.

eerorika
  • 232,697
  • 12
  • 197
  • 326
  • Ah, so array decay affects only statically declared arrays, and the dynamically declared ones can be always deleted with `delete[]`, for as long as I have some pointer to the first element? – user1079505 May 07 '23 at 22:11
1

The delete call within enlarge is deleting the int *x declared in main, as you're simply passing the pointer to a new function. This is why delete[] x in main gives you a double free; that pointer doesn't exist anymore.

Update: I should clarify that when you pass a pointer by value, you're effectively copying it. deleteing a copy of a pointer also deletes the original pointer.

fireshadow52
  • 6,298
  • 2
  • 30
  • 46