C Primer Plus (5th Edition)

2.4. const Qualifier

There are two problems with the following for loop, both concerning the use of 512 as an upper bound.

for (int index = 0; index != 512; ++index) { // ... }

The first problem is readability. What does it mean to compare index with 512? What is the loop doingthat is, what makes 512 matter? (In this example, 512 is known as a magic number, one whose significance is not evident within the context of its use. It is as if the number had been plucked by magic from thin air.)

The second problem is maintainability. Imagine that we have a large program in which the number 512 occurs 100 times. Let's further assume that 80 of these references use 512 to indicate the size of a particular buffer but the other 20 use 512 for different purposes. Now we discover that we need to increase the buffer size to 1024. To make this change, we must examine every one of the places that the number 512 appears. We must determinecorrectly in every casewhich of those uses of 512 refer to the buffer size and which do not. Getting even one instance wrong breaks the program and requires us to go back and reexamine each use.

The solution to both problems is to use an object initialized to 512:

int bufSize = 512; // input buffer size for (int index = 0; index != bufSize; ++index) { // ... }

By choosing a mnemonic name, such as bufSize, we make the program more readable. The test is now against the object rather than the literal constant:

index != bufSize

If we need to change this size, the 80 occurrences no longer need to be found and corrected. Rather, only the one line that initializes bufSize requires change. Not only does this approach require significantly less work, but also the likelihood of making a mistake is greatly reduced.

Defining a const Object

There is still a serious problem with defining a variable to represent a constant value. The problem is that bufSize is modifiable. It is possible for bufSize to be changedaccidentally or otherwise. The const type qualifier provides a solution: It transforms an object into a constant.

const int bufSize = 512; // input buffer size

defines bufSize to be a constant initialized with the value 512. The variable bufSize is still an lvalue (Section 2.3.1, p. 45), but now the lvalue is unmodifiable. Any attempt to write to bufSize results in a compile-time error.

bufSize = 0; // error: attempt to write to const object

Because we cannot subsequently change the value of an object declared to be const, we must initialize it when it is defined:

const std::string hi = "hello!"; // ok: initialized const int i, j = 0; // error: i is uninitialized const

const Objects Are Local to a File By Default

When we define a nonconst variable at global scope (Section 2.3.6, p. 54), it is accessible throughout the program. We can define a nonconst variable in one file andassuming an appropriate declaration has been madecan use that variable in another file:

// file_1.cc int counter; // definition // file_2.cc extern int counter; // uses counter from file_1 ++counter; // increments counter defined in file_1

Unlike other variables, unless otherwise specified, const variables declared at global scope are local to the file in which the object is defined. The variable exists in that file only and cannot be accessed by other files.

We can make a const object accessible throughout the program by specifying that it is extern:

// file_1.cc // defines and initializes a const that is accessible to other files extern const int bufSize = fcn(); // file_2.cc extern const int bufSize; // uses bufSize from file_1 // uses bufSize defined in file_1 for (int index = 0; index != bufSize; ++index) // ...

In this program, file_1.cc defines and initializes bufSize to the result returned from calling the function named fcn. The definition of bufSize is extern, meaning that bufSize can be used in other files. The declaration in file_2.cc is also made extern. In this case, the extern signifies that bufSize is a declaration and hence no initializer is provided.

We'll see in Section 2.9.1 (p. 69) why const objects are made local to a file.

Nonconst variables are extern by default. To make a const variable accessible to other files we must explicitly specify that it is extern.

Exercises Section 2.4

Exercise 2.22:

The following program fragment, while legal, is an example of poor style. What problem(s) does it contain? How would you improve it?

for (int i = 0; i < 100; ++i) // process i

Exercise 2.23:

Which of the following are legal? For those usages that are illegal, explain why.

(a) const int buf; (b) int cnt = 0; const int sz = cnt; (c) cnt++; sz++;

Категории