Previous | Table of Contents | Next |
A function such as this version of operator<< is called an applicator because it applies its argument to the file it represents. The library has a large variety of manipulators that control various aspects of formatting.
This entire discussion of the I/O library is oversimplified in at least one important respect: All the I/O library functions are really templates so that they can work on different kinds of characters. So, for example, the name ostream is really an abbreviation for basic_ostream<char>. Similarly, the name wostream is an abbreviation for basic_ostream<wchar_t>, and if a system has some complicated notion of characters that includes font, size, and other magic, it should be possible to use the standard I/O library with those characters too.
Of course, not all I/O must be done with << and >>; those operators are intended purely for human-readable I/O. The library also provides a wide selection of functions for doing I/O a character at a time, a line at a time, or in other units.
Strings are part of the standard library because otherwise every project would have its own way of defining them. Like the I/O library, the string library is really based on templates, so that the name string is really an abbreviation of basic_string<char>. The string library is mostly straightforward. Strings can vary in length, with the memory for them being dynamically allocated. It is fairly common to construct a string from a null-terminated character array, and there are several ways to pick the individual characters out of a string once the string has been constructed.
Operations on strings include assignment, concatenation, comparison, and assorted operations for finding characters within strings that have particular properties. For example, there is a fast operation to find the first character in a string that is also a character of some other string.
As a small example, here is a function that takes a string s and an unsigned integer n and replicates the string n times:
string repeat(const string& s, unsigned n) { string result; while (n) { result += s; --n; } return result; }
This function is remarkable in that it is unremarkable: The only part of it that might not be obvious is the use of += for concatenation. By analogy with numbers,
result += s
is equivalent to
result = result + s
except that result is evaluated only once. This distinction is important here for efficiency reasons: If the library knows that the program is intending to concatenate s onto the end of result, it will be able to so do much more efficiently than if it had to form a brand new string to hold result + s and then copy that string into result.
If we are at all concerned about efficiency, however, there is one more thing we should do: After saying
string result;
we should say
result.reserve(s.size() * n);
This causes the library to preallocate enough memory for the result object to hold all the characters in the result. As far as the actual value of result goes, this call to reserve makes no difference. But by preallocating the memory, reserve guarantees that the successive calls to += will not cause reallocation of the entire result string. The preallocation might therefore make the difference between a linear and a quadratic algorithm.
C++ has an assortment of library functions, such as sin, cos, and sqrt, that are inherited from C. These functions are part of the library because it is hard to implement them both portably and efficiently. Moreover, if the compiler knows something about the standard library, it can detect when programs are using these functions and generate appropriate machine instructions directly.
In addition, C++ has two families of classes that are intended for more general numeric computation. One handles complex arithmetic; the other handles arrays in a style that can be efficiently implemented on supercomputers.
Complex arithmetic is not built into C++. Instead, there is a library template class complex that is instantiated with the appropriate element type. Thus we can refer to complex<float>, complex<double>, and so on.
Having complex arithmetic as part of the library is almost as convenient as it would be if complex arithmetic were built into the language. The main disadvantage is that there is no special form for complex constants. However, it is possible to write expressions such as complex<double>(3, 4), which are not particularly inconvenient.
The numeric array class valarray is intended for high-performance numeric applications, particularly in the presence of optimizing compilers for special-purpose hardware. The idea is to restrict the operations on such arrays so that compilers can make plausible assumptions about how they will be used, and also to offer commonly used numeric array operations that might not generalize well to arrays of other types.
For example, if we say
valarray<double> v1, v2, v3;
and then subsequently give appropriate values to v1 and v2, then
v3 = v1 + v2;
will add the corresponding elements of v1 and v2 and store each element of the result in v3.
The valarray classes offer only one-dimensional arrays. However, they have auxiliary classes that are intended to make it both easy and efficient to simulate the appearance of multidimensional arrays. For example, one of these auxiliary classes is called slice; among its constructors is one that takes three integers representing an initial value, a count, and a distance. The idea is that a slice represents a sequence of equally spaced elements within an array, which might be used to represent (part of) a row, column, or diagonal.
For example, suppose we have a valarray with 100 elements:
valarray<double> v(100);
Then we can view it as a one-dimensional array with 100 elements, but we can also view it as a matrix with ten rows and ten columns.
If we view v as a matrix, then the first row comprises elements 0, 1, ..., 9. We can use v[slice(0, 10, 1)] to refer to the elements of that row. Here 0 is the index of the initial element, 10 is the number of elements, and 1 is the distance between consecutive elements.
Previous | Table of Contents | Next |