Unlike Java, C++ arrays can be allocated on the stack. Java arrays are a special type of object, hence they can only be dynamically allocated via "new" and therefore allocated on the heap.

In C++, the following code is perfectly valid. The array "localBuf" will be allocated on the stack when work is called, and it will be discarded when work exits:

void work( )
{
    double localBuf[30];
    for (int i=0 ; i<30 ; i++)
        localBuf[i] = sqrt(i);
    …
    // as this function exits, localBuf is discarded along with the stack frame
}

Be cautious if you are trying to use "large" stack-allocated arrays. In most (and probably all) runtime systems, stack-allocated arrays will not get properly allocated if the memory required is larger than some system-dependent threshold. Programs that attempt to stack-allocate arrays requiring more than this threshold will therefore typically crash as soon as they try to use the array. Worse yet, you will receive no compilation error or warning; the program will just crash when run. The solution is to allocate large arrays on the heap instead, being sure to delete them when they are no longer needed. (Deletion of dynamically allocated memory is discussed in the Memory management section.)

Some C++ compilers allow arrays whose size is not known until runtime to be stack-allocated as well. For example:

void createAndUseAnArray(int size)
{
    double buf[size];
    useTheArray(buf, size);
    …
}

Like "localBuf" in the "work" function above, "buf" will be stack-allocated and deleted as "createAndUseAnArray" exits. While g++ allows this, other compilers (e.g., the compilers in MS Visual Studio) do not. Moreover, Stroustrup's original specification of the language as well as most C++ standards specifications specify that the array size for a stack-allocated array must be a compile-time constant. For these reasons alone, stack allocating arrays whose size is not known at compile time is not recommended. Moreover, programs that unconditionally attempt to stack-allocate arrays whose size is not known until runtime can easily crash if this runtime-determined size turns out to be too large as just described above.

In summary, the fact that C++ allows stack-allocated arrays is a useful convenience for relatively small arrays whose size is known at compile time. For large arrays and/or arrays whose size is not known until runtime, you should always dynamically allocate them on the heap, explicitly deleting them when they are no longer needed.

Arrays of Class Instances

Since both objects and arrays can be stack-allocated, it is possible to have a stack-allocated array of object instances! For example, if Widget is a class, then we can say:

void widgetOperations()
{
    Widget widgets[20];
    …
}

This allocates 20 instances of Widget on the runtime stack. Furthermore – since C++ mandates that a constructor be called whenever an object is created – 20 constructor calls will be made, one for each of the 20 instances. Which constructor is called? The only constructor that can be called is the no-parameter constructor. This is part of what makes the no-parameter constructor "special" as mentioned in the Classes section. In fact, if class Widget does not have a no-parameter constructor, the declaration "Widget widgets[20];" will be flagged as a compilation error.

Another thing that makes the no-parameter constructor "special" is that C++ will automatically create a no-parameter constructor (with an empty body) if and only if you do not declare any other constructors in the class. So for example, if class Widget were declared as:

class Widget
{
public:
    void foo();
private:
    int bar;
};

the compiler will create a no-parameter constructor, and the declaration in widgetOperations above would successfully compile.

On the other hand, if class Widget were declared as:

class Widget
{
public:
    Widget(int x);
    void foo();
private:
    int bar;
};

the compiler will not create a no-parameter constructor, and the declaration in widgetOperations above would result in a compilation error!

These same comments apply if we dynamically allocate the array as will be discussed in the Basic Pointer Use and Memory management sections. For example:

Widget* widgets = new Widgets[20]; // 20 no-parameter constructor calls are made

If you wish to allocate an array on the runtime stack and allow each element to be created using a constructor other than the no-parameter constructor, the base type of the array must be "pointer to Widget" (see the Basic Pointer Use section). Once created, you can then dynamically allocate each instance using whatever constructor you desire. In this case, the array is on the runtime stack, but each element is placed in the heap. This approach in C++ would look like:

Widget* widgets[20]; // no constructors called since no Widget instances are created
for (int i=0 ; i<20 ; i++)
    widgets[i] = new Widget(3*i - 1);

If the size of the Widget array is not known at compile time and/or is "large", you do:

Widget** widgets = new Widget*[desiredSize];
for (int i=0 ; i<desiredSize ; i++)
    widgets[i] = new Widget(3*i - 1);

If this array is not returned to the caller as will be described next, then it must be deleted in this same context using code like the following. (The syntax and use of the delete operator is discussed in the Memory management section on the left.)

for (int i=0 ; i<desiredSize ; i++)
    delete widgets[i];
delete [] widgets;

Returning Created Arrays to the Caller

If an array created in a function is to be used after the function returns (e.g., if the array pointer will be stored in a persistent data structure and/or if it is to be returned as the function return value), you must explicitly allocate it on the heap using "new". This applies to both arrays of primitive types as well as arrays of class instances. Using an array of double as an example:

double* createInitializeAndReturnAnArray(int size)
{
    double* buf = new double[size]; // "buf" CANNOT be stack-allocated, regardless of "size"!
    for (int i=0 ; i<size ; i++)
        buf[i] = 0.0;
    // Caller will be responsible for returning the
    // array to free storage when it is done with it.
    return buf;
}

This variation introduces the idea of memory management (i.e., "returning the array to free storage") – an important topic that is discussed in the Memory management section.