C and C++ language linkage are the only specifiers required by the C++ Standard. But implementations have the option of providing additional language linkage specifiers.
Storage Schemes and Dynamic Allocation
You’ve seen the five schemes, excluding threaded memory, C++ uses to allocate memory for variables (including arrays and structures). They don’t apply to memory allocated by using the C++ new operator (or by using the older C malloc() function). We call that kind of memory
Although the storage scheme concepts don’t apply to dynamic memory, they do apply to automatic and static pointer variables used to keep track of dynamic memory. For example, suppose you have the following statement inside a function:
float * p_fees = new float [20];
The 80 bytes (assuming that a float is 4 bytes) of memory allocated by new remains in memory until the delete operator frees it. But the p_fees pointer passes from existence when program execution exits the block containing this declaration. If you want to have the 80 bytes of allocated memory available to another function, you need to pass or return its address to that function. On the other hand, if you declare p_fees with external linkage, the p_fees pointer will be available to all the functions following that declaration in the file. And by using the following in a second file, you make that same pointer available in the second file:
extern float * p_fees;
Note
Memory allocated by new is typically freed when the program terminates. However, this is not always true. Under some less robust operating systems, for example, in some circumstances a request for a large block of memory can result in a block that is not deleted automatically when the program terminates. The best practice is to use delete to free memory allocated by new.
Initialization with the new Operator
What if you want to initialize a variable as part of the dynamic memory allocation? With C++98, you can do so in some instances. C++11 expands what is possible. Let’s look first at what has been possible.
If you wish to create and initialize storage for one of the scalar built-in types, such as int or double, you can do so by following the desired type with an initialization value enclosed in parentheses:
int *pi = new int (6); // *pi set to 6
double * pd = new double (99.99); // *pd set to 99.99
The parentheses syntax also can be used with classes having suitable constructors, but we haven’t got that far yet.
To initialize an ordinary structure or an array, however, you need C++11 and list-initialization using braces. The new standard allows the following:
struct where {double x; double y; double z;};
where * one = new where {2.5, 5.3, 7.2}; // C++11
int * ar = new int [4] {2,4,6,7}; // C++11
With C++11, you also can use the brace initialization for single-valued variables:
int *pin = new int {}); // *pi set to 6
double * pdo = new double {99.99}; // *pd set to 99.99
When new Fails
It may be that new can’t find the requested amount of memory. For its first decade, C++ handled that eventuality by having new return a null pointer. Currently, however, new throws a std::bad_alloc exception. Chapter 15, “Friends, Exceptions, and More,” provides some short examples showing how each approach works.
new: Operators, Functions, and Replacement Functions
The new and new[] operators call upon two functions:
void * operator new(std::size_t); // used by new
void * operator new[](std::size_t); // used by new[]
These are termed
void operator delete(void *);
void operator delete[](void *);
They use the operator-overloading syntax discussed in Chapter 11, “Working with Classes.” The std::size_t is a typedef for some suitable integer type. A basic statement such as
int * pi = new int;
gets translated into something like this:
int * pi = new(sizeof(int));
And the statement
int * pa = new int{40];
gets translated into something like this:
int * pa = new(40 * sizeof(int));
As you’ve seen, a statement with a new operator can also provide initialization values, so, in general, using the new operator may do more than just call the new() function.
Similarly,
delete pi;
invokes the following function call: