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 stack, whereas the memory allocated by new is in a region called the heap or free store. Chapter 9 discusses this a bit further.

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 null pointer. C++ guarantees that the null pointer never points to valid data, so it is often used to indicate failure for operators or functions that otherwise return usable pointers. The if statement, discussed in Chapter 6, helps you deal with this possibility. For now, the important point is that C++ provides the tools to detect and respond to allocation failures.

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 free, can then be reused by other parts of the program. You use delete by following it with a pointer to a block of memory originally allocated with new:

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 memory leak—that is, memory that has been allocated but can no longer be used. If a memory leak grows too large, it can bring a program seeking more memory to a halt.

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.

Перейти на страницу:

Все книги серии Developer's Library

Похожие книги