Delete last element of dynamic array

Can I delete the last element of dynamic array using delete operator ?
example:
1
2
3
4
5
6
7
8
9
10
int main(){
  int n;
  cin >> n;
  int *arr = new int[n];
  for(int i = 0; i < n; i++)
     arr[i] = i;
  delete &arr[n-1];
  n--;
  return 0;
}

is previous code correct or not and why ?
Last edited on
this is not correct. delete does not work like this. Delete destroys exactly what a call to new allocated; under the hood, some values are saved for delete to work properly (the compiler stores and hides from you the # of bytes that new allocated for this pointer -- that is why delete[] works without a value provided to its size!!). Trying to delete something else will not end well. It may compile, it may even run sometimes, but this is no good.

Last edited on
It is undefined (according to cppreference).
Can I delete the last element of dynamic array using delete operator ?

It seems you can’t delete the last element of a C-style dynamic array using delete.
The following program crashes:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <iostream>


void printArr(const int * const arr, int size);


int main()
{
    std::cout << "How many elements? ";
    int n;
    std::cin >> n;
    int * const arr = new int[n];
    for(int i = 0; i < n; ++i) {
        arr[i] = i;
    }
    printArr(arr, n);
    delete &arr[n-1];
    --n;
    printArr(arr, n);
    return 0;
}


void printArr(const int * const arr, int size)
{
    for (int i {}; i < size; ++i) {
        std::cout << arr[i] << ' ';
    }
    std::cout << '\n';
}


is previous code correct or not

It’s not correct.

and why ?

1) It does not compile.
The first judge of any code is the compiler: if the compiler rejects it, it means it’s wrong (well, ok, sometimes there are compiler issues). So, in general, never ask about a code that doesn’t compile.

2) Curly braces don’t match:
int main()[ // <-- this must be a curly parenthesis

3) To use std::cin you must include <iostream>

4) It’s not logic.
If it were possible to free single memory areas from an array, when the compiler is requested to delete the array what should it do?
I mean, if you reserve space for an array of five ints:
int * const arr { new int[5] };
and then, by means of some trick, you could free the space of two ints, that free space could be allocated for something else.
What would happen when you ask:
delete[] arr ?
I don't know but delete operator doesn't affect in the value that stored in address, it just frees the address.
So i think delete will do nothing in this case :\
Or compiler will crush ?
And by looking at jonnin answer, he said "Delete destroys exactly what a call to new allocated"
so this code allocates the array's elements by new keyword so that i can use delete with any element i want and compiler will run successfully.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>

using namespace std;

int main(){
    int n;
    cin >> n;
    int **x = new int*[n];
    for(int i = 0; i < n; i++){
        x[i] = new int(i+10);
    }

    for(int i = 0; i < n; i++){
        cout << x[i][0] << endl;
    }

    cout << "done";

    delete[] x;
    return 0;
}

In all i am beginner and not sure my comment is correct or not
That program deallocates on line 19 the array that was allocated on line 8.
However, you don't delete the n separately allocated integers. That would be a memory leak.

Your original program could use std::vector:
http://www.cplusplus.com/reference/vector/vector/pop_back/
1
2
3
4
5
6
7
8
9
10
11
#include <vector>
#include <iostream>
int main(){
  int n;
  std::cin >> n;
  std::vector<int> arr(n);
  for ( int i = 0; i < arr.size(); ++i )
     arr[i] = i;

  if ( !arr.empty() ) arr.pop_back();
}


You could "pretend" that the array is shorter than it is:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>
int main(){
  int capacity;
  std::cin >> capacity; // true size
  int* arr = new int [capacity];

  int size = capacity; // apparent size
  for ( int i = 0; i < size; ++i ) 
     arr[i] = i;

  if ( 0 < size ) --size;

  for ( int i = 0; i < size; ++i )
    std::cout << arr[i] << ' '; // See? The last one is "gone"

  delete [] arr;
}

Ok i got it thank you all
But i have one question yet
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>

using namespace std;

int main(){
    int n;
    cin >> n;
    int **x = new int*[n];
    for(int i = 0; i < n; i++){
        x[i] = new int(i+10);
    }

    for(int i = 0; i < n; i++){
        cout << x[i][0] << endl;
    }
    delete x[n-1];

    delete[] x;
    cout << "done";
    return 0;
}

This code run successfully
I allocated each element by itself and all allocated as a block
So is it correct ?(regardless of it's good practice or not)
ahmad alghadban wrote:
So is it correct ?

No.

You have created a memory leak for n-1 integers.


If you change
delete x[n-1];
to
for ( int i = 0; i < n; i++ ) delete x[i];
you will be OK.

Otherwise the heap memory that was pointed to by x[0], x[1], ..., x[n-2] will be henceforth inaccessible.
Ok .. why will be inaccessible ?
what does happen in compiler and ram ?
If you delete the pointer (which is what delete[] x will do in this instance) then (a) your program will have no record of where the data will be; (b) the operating system will not have been sent any request to give up that memory.

So, gradually (or occasionally otherwise), you will run out of memory until your program closes.
And by looking at jonnin answer, he said "Delete destroys exactly what a call to new allocated"
so this code allocates the array's elements by new keyword so that i can use delete with any element i want and compiler will run successfully.

you have to read everything I said, not pick and choose :)

NEW stores how many bytes it allocated.
DELETE reads that stored value and kills them all *when called on the same address as was allocated by new*.

If you call delete on anything you did not new (any other memory address) it is not correct. Calling it in the middle of a block of memory is wrong. Calling it on the address of a local stack variable is wrong. Calling it on null is ok, its wired to ignore it. You cannot use it with any element you want, you can only use it on the address that was given to you by new. No other address. It may "work" on a compiler with relaxed syntax, where I use the word "work" very loosely. That does not make it right; unfortunately c++ has a lot of things that are totally wrong that will compile and run and sometimes even "work".

The cause is the new/delete mechanics where it is storing the # of bytes for you. Addresses not returned by new don't have this counter and I believe will attempt to do something bad ... I think the # of bytes is stored at -X bytes from the pointer it gives you. that is, new gets 1004 bytes from the OS. it uses the first, I dunno, lets say 4 bytes as an integer of how many it gave you. It returns to you the address of that memory + 4, and gives you 1000 bytes in your array. When you delete it with the correct address, it backs up 4, sees 1004, and returns that block of 1004 back to the OS. If you called delete on array[50], it backs up 4 bytes, gets a 'random' (its really your data recast as int) number, and attempts to return THAT. If that value were 10 million, you would have a problem....
Last edited on
To summarize:

The only legal values to pass to delete are nullptr and a value that was previously returned by new.

Memory allocated by new must be deleted with delete, and memory allocated by new[] must be deleted by delete[]. You can't mix and match.

Every call to new or new[] at runtime must have exactly one matching call to delete or delete[] at runtime. If you have no matching call, then you will leak memory and the program may be incorrect because destructors won't get called. If you have multiple matching calls then the behavior is undefined.
So is it correct ?

No.

#1 Deallocate everything that you have allocated. Leave no byte behind.
#2 Avoid dangling pointers.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
    int **x = new int* [n]; // allocation A
    for ( int i = 0; i < n; i++ ) {
        x[i] = new int (i+10); // allocation Bn
    }

    // operations on x

    delete x[n-1]; // deallocate one of Bn
    x[n-1] = nullptr; // #2 make that pointer "safe"

    // operations on x

    // cleanup: #1
    for ( int i = 0; i < n; i++ ) {
        delete x[i]; // deallocate Bn
    }
    delete[] x; // deallocate A 
Topic archived. No new replies allowed.