8

I can't understand the end of this code (array = 0;):

#include <iostream>

int main()
{
    std::cout << "Enter a positive integer: ";
    int length;
    std::cin >> length;

    int *array = new int[length];

    std::cout << "I just allocated an array of integers of length " << length << '\n';

    array[0] = 5; // set element 0 to value 5

    delete[] array; // use array delete to deallocate array
    array = 0; // use nullptr instead of 0 in C++11

    return 0;
}

At the end, a dynamically allocated array is deleted (returned to OS) and then assigned a value of 0.

Why is this done? After array has been returned to the OS, there is no need to assign it a value of 0, right?

Code from: http://www.learncpp.com/cpp-tutorial/6-9a-dynamically-allocating-arrays/

Andre Kampling
  • 5,476
  • 2
  • 20
  • 47
bob
  • 101
  • 5
  • 2
    It sets a valid (but null) pointer to array to avoid to have dangling pointer. So later, we can test `array` before to use it. if the pointer is no longer used, it is indeed unneeded. – Jarod42 Aug 28 '17 at 08:13
  • int *array, as a pointer, still holds info on address it pointed to, even though objects are deallocated. Since that space no longer belongs to that pointer, set it to 0 so that you can't access some random data. – metamorphling Aug 28 '17 at 08:15
  • 3
    Using `std::vector` would avoid those manual memory management. – Jarod42 Aug 28 '17 at 08:19
  • Variables are only known at compile time. You are deleting *values* – Basile Starynkevitch Aug 28 '17 at 08:27
  • 1
    Read the C++ core guidlines: [R.11: Avoid calling new and delete explicitly](https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#Rr-newdelete) –  Aug 28 '17 at 08:36
  • 1
    In this specific case it is redundant but some people like to do this after `delete` as a general rule – M.M Aug 28 '17 at 08:57
  • I would just skip this and continue with [Chapter 6.16 - An introduction to std::vector](http://www.learncpp.com/cpp-tutorial/6-16-an-introduction-to-stdvector/) – Bo Persson Aug 28 '17 at 11:46

4 Answers4

16

After array has been returned to the OS, there is no need to assign it a value of 0, right?

You're right it is not needed because the memory is freed (deallocated) by the operator delete. But think of a case where you may use the pointer in another place in your code (functions, loops, etc.) after you use delete[] on it.

The array variable still holds the address of the old allocation after the delete[] statement was called (dangling pointer). If you would access that address you would get undefined bahaviour (UB) because the memory is no longer yours, in most of the cases your program would crash.

To avoid that you do a null pointer check like:

if (array != nullptr)
{
   /* access array */
   ...
}

which is checking the pointer against the address 0 which represents an invalid address.

To make that check possible you set the pointer to nullptr or NULL if C++11 is not available. The nullptr keyword introduces type safety because it acts like a pointer type and should be preferred over the C-like NULL. In pre C++11 NULL is defined as integer 0, since C++11 it's an alias to nullptr.
To define your own nullptr to use it for pre C++11 compiler look here: How to define our own nullptr in c++98?


An interesting fact about delete or delete[] is that it is safe to use it on a nullptr. It is written at point 2 on cppreference.com or at this SO answer.

operator delete, operator delete[]

2) [...] The behavior of the standard library implementation of this function is undefined unless ptr is a null pointer or is a pointer previously obtained from the standard library implementation of operator new[](size_t) or operator new[](size_t, std::nothrow_t).

Andre Kampling
  • 5,476
  • 2
  • 20
  • 47
  • 3
    Yes, **if** your design calls for reuse of pointers, then you need a flag to tell you that the pointer does not point to something valid; that's what a null pointer is for. It should **not** be automatically used after deleting something. In particular, it's silly to write a destructor that deletes an allocated block then sets the pointer to null, but that's often seen in beginners' code. – Pete Becker Aug 28 '17 at 12:21
  • 1
    @PeteBecker Why would that be silly? Isn't it good practice to always null your pointers after delete, in case reuse is introduced later? What's the downside? – Sossisos Aug 28 '17 at 13:00
  • 2
    @Sossisos -- the reason that it's **silly** is that after the destructor runs the object **does not exist** and there **is no pointer** to reuse. The downside is that it makes whoever wrote that code look like they code by slogan instead of thinking. – Pete Becker Aug 28 '17 at 16:50
  • @PeteBecker Ah, my apologies, I misread, I thought the "silly" was in regards to nulling pointers as a matter of course, not specifically doing it in the destructor. Anyway, I read some of the linked articles here on why nulling shouldn't be done as a matter of course, and understand the reasoning now (even though I don't quite agree with it). Thank you for your time :) – Sossisos Aug 29 '17 at 07:17
9

We are setting pointers to NULL (0) to avoid dangling pointers (pointer is still pointing to same memory which is no longer yours). In case of local variables it is not that useful if function doesnt continue after delete (so its obvious pointer won't be reused). In case of global/member poitners its good practice to avoid bugs.

Accessing already deleted pointer may lead to overwriting/reading random memory (it might be more dangerous than crash) and causes undefined behavior, while accessing NULL pointer will immediatelly crash.

Since you should use nullptr because its defined as pointer type while NULL is more int type and improves type safety + resolves ambiguous situations.

In case of double deleting pointer, its safe to use delete on nullptr and nothing happens but if you delete already deleted non-null pointer, it will cause undefined behavior and most likely program will crash.

In you should avoid using pure pointers since there are STL containers (which frees their resources them self (RAII)) for this usage or smart pointers.

std::vector<int> array{1,2,3,4,5};
kocica
  • 6,412
  • 2
  • 14
  • 35
  • 1
    Re: "good practice to avoid bugs" -- best practice to avoid bugs is to **design** code properly and **implement** the design. Automatically setting pointers to null _just in case someone gets careless_ does **not** avoid bugs; **designing** and **implementing** a system that uses null to signify that a pointer points to nothing does. – Pete Becker Aug 28 '17 at 12:24
3

This is done so that the pointer is set to NULL (whether in C++, we prefer nullptr, since NULL and 0 may be different things).

This tactic eliminates the possibility of a dangling pointer, because the array may have been deleted, but that doesn't mean that it's set to NULL.

If we don't do that, we run the risk of checking whether the pointer is NULL or not (latter in our code), we will see that it's not NULL, wrongly believe that the pointer is OK to be accessed, and cause Undefined Behavior.

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
gsamaras
  • 71,951
  • 46
  • 188
  • 305
1

You assign to a value commonly known as "invalid address", i.e. NULL, 0 or the pointer type nullptr, because otherwise there is no way you can know whether you pointer points to an invalid address. In other words when you delete[] your array your pointer "doesn't know" that it is pointing to a no longer usable memory address.

Andre Kampling
  • 5,476
  • 2
  • 20
  • 47
Ziezi
  • 6,375
  • 3
  • 39
  • 49