Avoid New and Delete for Dynamic Arrays
This note continues the discussion I started last month about teaching C++. In it, I have been advocating the standard vector template instead of built-in arrays.
One nice attribute of vectors is that you don't need to know the length of a vector during compilation. However, some people argue — and I've seen teachers and textbooks that advocate — using new and delete expressions as an alternative to arrays.
On the surface, new and delete expressions are almost as easy to use as vectors. For example, instead of writing
int size;
cin >> size;
int numbers[size]; // C++ does not allow this
you can write
int size;
cin >> size;
int* numbers = new int[size];
to allocate a dynamic array with size elements. And indeed, this example isn't much more complicated than writing
int size;
cin >> size;
vector<int> numbers(size);
at least not on the surface. Of course, if you're going to use new, you should use delete as well, so the code should really look like this:
int size;
cin >> size;
int* numbers = new int[size];
...
delete[] numbers;
In this example, the teacher must explain why delete is needed for numbers even though it's not needed for size; why the definition of numbers has to mention int twice; why the * is there; and why delete needs the [] after it. Still, on the surface, this code doesn't look like it's much harder than the corresponding code that uses arrays.
The trouble is that code that looks simple on the surface can conceal deeper problems, and these problems can encourage students to think in ways that are less useful than they might be. For example, the code examples I've written so far do not occur in isolation. Rather, any executable code must be part of a function. Let's sketch at least the outline of that function:
int main()
{
int size;
cin >> size;
int* numbers = new int[size];
...
delete[] numbers;
return 0;
}
We can now see that we allocate memory for our dynamic array at the beginning of main and free it at the end. What happens if the code represented by ... contains a return statement?
The answer is that the memory that we allocated is never freed. Of course, the operating system will free that memory for us — so long as main is the function involved. But now our students are encouraged to think that failure to free memory is acceptable. If the code is later moved from main
Although using new lets you defer setting the size of an array until runtime, programmers sometimes want to change an array's size after it has already been allocated. Suppose, for example, that we want to change the number of elements in numbers from size to newsize. We might do so as follows:
int newsize;
// Free the old array and reset the pointer
delete[] numbers;
// Allocate space for the new array
int* newnumbers = new int[newsize];
// Copy the elements of the old array
for (int i = 0; i < size; ++i)
newnumbers[i] = numbers[i];
numbers = newnumbers;
We have just used six lines of code to accomplish what we could have done in a single line if we were using vectors:
numbers.resize(newsize);
Moreover, these six lines of code conceal a serious bug, which I am leaving to you as an exercise to find.
Probably the most common reason to want to change the size of a dynamic array is to append a single element to it. Of course, the standard vector template makes it both easy and efficient to do so:
numbers.push_back(newnumber);
One might think that this operation would be horrendously slow, because it must copy the entire vector each time we want to append an element. However, vectors quietly allocate more memory than is strictly needed, and use that memory to give the vector room to grow. Only when the vector outgrows its memory does it ask for more. There is no direct support in C++ for using new and delete to allocate extra space in this way; vector does so by using different memory-allocation facilities. Therefore, if you were to try to imitate this behavior using new and delete, you would quickly find yourself in trouble.
In short, even though it may seem at first that new and delete are an alternative to built-in arrays that is almost as convenient as using the vector template, vectors have several significant advantages over new and delete. They take care of freeing memory automatically; they make it easy (and less error-prone) to change the size of a vector after it has been allocated; and they manage memory more efficiently than it is possible to do by using new and delete.
Of course, new and delete have their place; but that place is not substituting for built-in arrays or vectors. In fact, I think that it is wise for most C++ programmers to avoid using new and delete with arrays altogether, reserving them for dealing with objects that need to outlive the scope that created them.

