2
int main(){
    char *Allocation;
    Allocation = new char[8]; //here is out first allocation;

    delete[] Allocation;      //after while we delete it;
    
    Allocation = new char[16];//then we allocate some chunk of memory again to our pointer;

    delete[] Allocation;      //then finally we delete our second allocation;
}

Is this valid in C++? Does the first allocation affect the second allocation? Can I allocate a new memory block to a deleted pointer?

Benjamin Buch
  • 4,752
  • 7
  • 28
  • 51
  • 5
    Yes it's perfectly valid. Variables are just variables, you can reuse them. `delete[]` has no effect at all on a variable, just on the memory (or objects) that the variable happens to be pointing to. – john Jun 10 '23 at 08:23
  • 8
    Yes, it is perfectly fine. In reality, `delete` doesn't "delete the pointer", but deletes what is pointed to. The pointer itself is still there. – BoP Jun 10 '23 at 08:23
  • 2
    @john Technically, `delete [] Allocation` *can* affect the value of `Allocation`, but is not required to (for example, reassigning it to NULL is permitted but not required - and, in practice, some implementations do that when debugging). If the value of `Allocation` is changed, that change will not prevent subsequent reassignment. – Peter Jun 10 '23 at 08:38
  • 2
    @Peter Interesting. I didn't know that. More [details](https://stackoverflow.com/questions/45149756/is-delete-allowed-to-modify-its-parameter) – john Jun 10 '23 at 08:45
  • It is allowed, but consider using `auto allocation = std::make_unique(8ul);` and then you can use `allocation.reset(std::make_unique(16ul));` to reallocated (new/delete not recommended in C++). Another option to avoid new is to use `std::vector Allocation(8ul);` and then use `Allocation.resize(16u);` to increase the allocated capacity of the vector. – Pepijn Kramer Jun 10 '23 at 09:34
  • @PepijnKramer `std::unique_ptr::reset` takes a raw pointer, not a `std::unique_ptr` object. You need to the move assignment operator instead: `auto allocation = std::make_unique(8); allocation.reset(); allocation = std::make_unique(16);` (The second statement is only necessary, if the memory should be freed early; move assignment will free previously owned memory automatically). – fabian Jun 10 '23 at 10:31
  • @fabian I stand corrected :) – Pepijn Kramer Jun 10 '23 at 10:34

2 Answers2

3

tl;dr Yes, that's perfectly fine.

You have to distinguish between the actual value in memory and the value of the pointer variable that points to this actual value in memory.

new provides the actual value in memory (which is not bound to a variable) and returns its address. This returned address is then set by assignment as the value of the variable Allocation.

With delete you remove the actual value from memory. But this usually does not affect the value of the variable Allocation. The address is therefore retained, but must no longer be dereferenced. It is undefined what happens if you do this anyway.

Therefore it is recommended to assign a nullptr (null pointer) to Allocation right after calling delete. Some implementations do assign a nullptr implicitly after delete if the program is compiled in debug mode. Therefore the usually above.

A nullptr is just the address with the value 0. An access on this address is always invalid, so its the common value to imply that a pointer doesn't point to a valid location.

So you can assign a different address as value to the variable Allocation at any time. The memory managed with new and delete exists independent of variables. These are only used for access.


By the way, you should initialize your variable Allocation with either a call to new or with a nullptr. Otherwise your variable Allocation may contain some random value

#include <iostream>

int main() {
    char* a = new char[8]; // contains address of valid value
    // or
    char* b = nullptr; // contains address to "nowhere"
    char* c{nullptr};  // also fine
    char* d(nullptr);  // also fine
    char* e{};         // also fine (implicit nullptr)

    // Bad:
    char* f; // may contain any address

    std::cout << std::hex
        << "a: " << reinterpret_cast<std::size_t>(a) << '\n'
        << "b: " << reinterpret_cast<std::size_t>(b) << '\n'
        << "c: " << reinterpret_cast<std::size_t>(c) << '\n'
        << "d: " << reinterpret_cast<std::size_t>(d) << '\n'
        << "e: " << reinterpret_cast<std::size_t>(e) << '\n'
        << "f: " << reinterpret_cast<std::size_t>(f) << '\n';

    // Note: C++ syntax is evil 
    char* g(); // function declaration, e{} was a variable definition
    char* h(std::nullptr_t); // also a function declaration, compare to d
                             // nullptr is a value
                             // std::nullptr_t is a type

    // Linker error: undefined reference to `g()'
    // std::cout << reinterpret_cast<std::size_t>(g) << '\n';

    delete[] a;
}

Live code at Compiler Explorer

Output:

a: 558bb9976eb0 (possible output, always a valid address value)
b: 0
c: 0
d: 0
e: 0
f: 3a66 (possible output, may have any address value)

Note that C++ distinguishes between initialization and assignment:

char* Allocation = new char[8]; // initialization 
Allocation = new char[8];       // assignment
Benjamin Buch
  • 4,752
  • 7
  • 28
  • 51
  • 2
    **If I recall correctly** (and I'm *not* a language lawyer), after `delete[] Allocation;` it is not legal even to check `if (Allocation) blah();`. So in addition to not being legal to dereference `Allocation` after it's been deleted, it's also not legal to even read the pointer value. And that goes for all copies of the pointer, `auto Alloc2 = Allocation;`. None of the platforms I use appear to have a problem doing this; but UB is thin ice upon which to build a house of cards. – Eljay Jun 10 '23 at 11:51
  • 2
    Here's an SO question/answer that talks about not even being allowed to read the value of the pointer after being `delete`d: https://stackoverflow.com/a/23621710/4641116 (there are many other discussions on SO about this same dusty corner of the language) – Eljay Jun 10 '23 at 12:03
  • 2
    @Eljay According to https://stackoverflow.com/a/45787047/4821621 this is actually undefined behavior, so in principle anything could actually happen when accessing the value by read. In real implementations it will always return either the old value or a `nullptr`. Thanks for bringing it to my attention! – Benjamin Buch Jun 10 '23 at 12:26
  • 1
    C++ has a lot of surprises and nuances! – Eljay Jun 10 '23 at 12:37
1

In cpp,it is completely valid to assign a new memory block to a deleted pointer. Second allocation does not get affected by the previously assigned memory block. We manage memory allocations and deallocations properly so as to avoid memory leaks and undefined behavior.