Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Professional C++ [eng].pdf
Скачиваний:
284
Добавлен:
16.08.2013
Размер:
11.09 Mб
Скачать

Chapter 13

If the two pointers you are casting are actually pointing to objects that are related through inheritance, the compiler will permit a static cast. However, as you read in Chapter 10, a dynamic cast is a safer way to accomplish a cast within an inheritance hierarchy.

const with Pointers

The interaction between the const keyword and pointers is a bit confusing, because it is unclear to what you are applying const. If you dynamically allocate an array of integers and apply const to it, is the array address protected with const, or are the individual values protected? The answer depends on the syntax.

If const occurs before the type, it means that the pointed-to value is protected. In the case of an array, the individual elements of the array are const. The following function receives a pointer to a const integer. The first line will not compile because the actual value is protected by const. The second line would compile, because the array itself is unprotected.

void test(const int* inProtectedInt, int* anotherPtr)

{

*inProtectedInt = 7; // BUG! Attempts to write to read-only value inProtectedInt = anotherPtr; // Works fine

}

To protect the pointer itself, the const keyword immediately precedes the variable name, as shown in the following code. This time, both the pointer and the pointed-to value are protected, so neither line would compile.

void test(const int* const inProtectedInt, int* anotherPtr)

{

*inProtectedInt = 7; // BUG! Attempts to write to read-only value

inProtectedInt = anotherPtr; // BUG! Attempts to write to read-only value

}

In practice, protecting the pointer is rarely necessary. If a function is able to change the value of a pointer that you pass it, it makes little difference. The effect will only be local to the function, and the pointer will still point to its original address as far as the caller is concerned. Marking a pointer as const is more useful in documenting its purpose than for any actual protection. Protecting the pointed-to value(s), however, is quite common to protect against overwriting shared data.

Array-Pointer Duality

You have already seen some of the overlap between pointers and arrays. Heap-allocated arrays are referred to by a pointer to their first element. Stack-based arrays are referred to by using the array syntax ([]) with an otherwise normal variable declaration. As you are about to learn, however, the overlap doesn’t end there. Pointers and arrays have a complicated relationship.

362

Effective Memory Management

Arrays Are Pointers!

A heap-based array is not the only place where you can use a pointer to refer to an array. You can also use the pointer syntax to access elements of a stack-based array. The address of an array is really the address of the 0th element. The compiler knows that when you refer to an array in its entirety by its variable name, you are really referring to the address of the 0th element. In this way, the pointer works just like a heap-based array. The following code creates an array on the stack, but uses a pointer to access the array.

int main(int argc, char** argv)

{

int myIntArray[10];

int* myIntPtr = myIntArray;

// Access the array through the pointer. myIntPtr[4] = 5;

}

The ability to refer to a stack-based array through a pointer is useful when passing arrays into functions. The following function accepts an array of integers as a pointer. Note that the caller will need to explicitly pass in the size of the array because the pointer implies nothing about size. In fact, C++ arrays of any form, pointer or not, have no built-in notion of size.

void doubleInts(int* theArray, int inSize)

{

for (int i = 0; i < inSize; i++) {

theArray[i] *= 2;

}

}

The caller of this function can pass a stack-based or heap-based array. In the case of a heap-based array, the pointer already exists and is simply passed by value into the function. In the case of a stack-based array, the caller can pass the array variable and the compiler will automatically treat the array variable as a pointer to the array. Both uses are shown here:

int main(int argc, char** argv)

{

int* heapArray = new int[4]; heapArray[0] = 1; heapArray[1] = 5; heapArray[2] = 3; heapArray[3] = 4;

doubleInts(heapArray, 4);

int stackArray[4] = {5, 7, 9, 11};

doubleInts(stackArray, 4);

}

363

Chapter 13

Even if the function doesn’t explicitly have a parameter that is a pointer, the parameter-passing semantics of arrays are uncannily similar to pointers’, because the compiler treats an array as a pointer when it is passed to a function. A function that takes an array as an argument and changes values inside the array is actually changing the original array, not a copy. Just like a pointer, passing an array effectively mimics pass-by-reference functionality because what you really pass to the function is the address of the original array, not a copy. The following implementation of doubleInts() changes the original array even though the parameter is an array, not a pointer.

void doubleInts(int theArray[], int inSize)

{

for (int i = 0; i < inSize; i++) { theArray[i] *= 2;

}

}

You may be wondering why things work this way. Why doesn’t the compiler just copy the array when array syntax is used in the function definition? One possible explanation is efficiency — it takes time to copy the elements of an array, and they potentially take up a lot of memory. By always passing a pointer, the compiler doesn’t need to include the code to copy the array.

To summarize, arrays declared using array syntax can be accessed through a pointer. When an array is passed to a function, it is always passed as a pointer.

Not All Pointers Are Arrays!

Since the compiler lets you pass in an array where a pointer is expected, as in the doubleInts() function shown earlier, you may be lead to believe that pointers and arrays are the same. In fact there are subtle, but important, differences. Pointers and arrays share many properties and can sometimes be used interchangeably (as shown earlier), but they are not the same.

A pointer by itself is meaningless. It may point to random memory, a single object, or an array. You can always use array syntax with a pointer, but doing so is not always appropriate because pointers aren’t always arrays. For example, consider the following code:

int* ptr = new int;

The pointer ptr is a valid pointer, but it is not an array. You can access the pointed-to value using array syntax (ptr[0]), but doing so is stylistically questionable and provides no real benefit. In fact, using array syntax with nonarray pointers is an invitation for bugs. The memory at ptr[1] could be anything!

Arrays are automatically referenced as pointers, but not all pointers are arrays.

364