RR: std::vector<> instead of new[]
One of the trickiest concepts for beginners in C++ (and other languages with low-level capability) is memory management, i.e., correct allocation and de-allocation of memory. I already discussed that in some cases memory management can be avoided, but of course at some point in the program memory allocation does need to be made. Here I discuss using the standard library std::vector<> container instead of the plain new[] and the advantages this approach gives.
The new[] approach
The C++ operator new[] allocates memory for a continuous sequence of objects in memory. A very simple example is:
double * a = new double[10];
The variable double * a allows access to this memory either by de-reference:
double c = *a;
or by the indexing operator:
double d = a[5];
The two approaches are equivalent since we are free to add an offset to a before de-referencing:
double d = *(a+5);
It is important to appreciate that besides allocating memory for objects, new[] must also somewhere keep track of how much memory was allocated so that this memory can be subsequently properly deleted.
The std::vector<> approach
The std::vector<> is a container from the c++ Standard Template Library (STL) which has a number of features. It, however, fundamentally has the same basic underlying function as new[], which is allocating memory for a continuous sequence of object.
This requirement that std::vector<> allocates objects in a continuous sequence in memory is occasionally under appreciated since the C++ standard was originally slightly ambiguous. This clarification however settles this matter. The implication is that memory allocated by new[] and std::vector<> is similar and can be used in an identical way.
But how can you access this memory as a simple pointer like we did above? The answer is simply to take the address of the first element of the vector:
// Allocates a vector of length 10
std::vector<double> v(10);
double *a = &v[0];
double d= a[5];
// and so on
Example
Here is an example of the program from previous article illustrating the use of std::vector<> instead of new[]
// Bojan Nikolic <bojan@bnikolic.co.uk>
//
// Improved example
#include <boost/random.hpp>
#include <iostream>
#include <vector>
void getRand(double *res,
size_t n)
{
boost::mt19937 rng(43);
static boost::uniform_01<boost::mt19937> zeroone(rng);
for(size_t i=0; i<n; ++i)
{
res[i]=zeroone();
}
}
int main(void)
{
const size_t n=10;
std::vector<double> r(n);
getRand(&r[0],n);
for(size_t i=0; i<n; ++i)
{
std::cout<<r[i]<<" ";
}
}
What is the advantage of this approach compared to the previous example? By using std::vector<> the memory is automatically deleted when r goes out of scope, unlike the previous example which actually had a memory leak. By automatically deleting the objects, the exception safety of the code increased too.
No pointer at all
The above discussion assumes that you want to access memory through a simple pointer. This is sometimes the case, especially when interfacing to lower level code. If simple pointers are not absolutely required, then one could of course simply pass references to the std::vector<>.
Summary
If you think you need to allocate memory using new[] consider using std::vector<> instead. It will:
- delete the memory automatically when the vector goes out of scope
- save you from forgetting to use delete[] instead of delete
You can still take the address of the first element and pass it as a simple pointer to, for example, interface to low level code.