cout << "value = " << *pt << ": location = " << pt << endl;
double * pd = new double; // allocate space for a double
*pd = 10000001.0; // store a double there
cout << "double ";
cout << "value = " << *pd << ": location = " << pd << endl;
cout << "location of pointer pd: " << &pd << endl;
cout << "size of pt = " << sizeof(pt);
cout << ": size of *pt = " << sizeof(*pt) << endl;
cout << "size of pd = " << sizeof pd;
cout << ": size of *pd = " << sizeof(*pd) << endl;
return 0;
}
Here is the output from the program in Listing 4.17:
nights value = 1001: location 0028F7F8
int value = 1001: location = 00033A98
double value = 1e+007: location = 000339B8
location of pointer pd: 0028F7FC
size of pt = 4: size of *pt = 4
size of pd = 4: size of *pd = 8
Of course, the exact values for the memory locations differ from system to system.
Program Notes
The program in Listing 4.17 uses new to allocate memory for the type int and type double data objects. This occurs while the program is running. The pointers pt and pd point to these two data objects. Without them, you cannot access those memory locations. With them, you can use *pt and *pd just as you would use variables. You assign values to *pt and *pd to assign values to the new data objects. Similarly, you print *pt and *pd to display those values.
The program in Listing 4.17 also demonstrates one of the reasons you have to declare the type a pointer points to. An address in itself reveals only the beginning address of the object stored, not its type or the number of bytes used. Look at the addresses of the two values. They are just numbers with no type or size information. Also note that the size of a pointer-to-int is the same as the size of a pointer-to-double. Both are just addresses. But because use_new.cpp declares the pointer types, the program knows that *pd is a double value of 8 bytes, whereas *pt is an int value of 4 bytes. When use_new.cpp prints the value of *pd, cout can tell how many bytes to read and how to interpret them.
Another point to note is that typically new uses a different block of memory than do the ordinary variable definitions that we have been using. Both the variables nights and pd have their values stored in a memory region called the
Out of Memory?
It’s possible that a computer might not have sufficient memory available to satisfy a new request. When that is the case, new normally responds by throwing an exception, an error-handling technique discussed in Chapter 15, “Friends, Exceptions, and More.” In older implementations new returns the value 0. In C++, a pointer with the value 0 is called the
Freeing Memory with delete
Using new to request memory when you need it is just the more glamorous half of the C++ memory-management package. The other half is the delete operator, which enables you to return memory to the memory pool when you are finished with it. That is an important step toward making the most effective use of memory. Memory that you return, or
int * ps = new int; // allocate memory with new
. . . // use the memory
delete ps; // free memory with delete when done
This removes the memory to which ps points; it doesn’t remove the pointer ps itself. You can reuse ps, for example, to point to another new allocation. You should always balance a use of new with a use of delete; otherwise, you can wind up with a
You should not attempt to free a block of memory that you have previously freed. The C++ Standard says the result of such an attempt is undefined, meaning that the consequences could be anything. Also you cannot use delete to free memory created by declaring ordinary variables:
int * ps = new int; // ok
delete ps; // ok
delete ps; // not ok now
int jugs = 5; // ok
int * pi = &jugs // ok
delete pi; // not allowed, memory not allocated by new
Caution
You should use delete only to free memory allocated with new. However, it is safe to apply delete to a null pointer.