The Double-Bounded Array

The examples in this section implement a simple abstraction present in many programming languages outside the C++ family. These languages allow the programmer to specify both an upper and lower bound on the subscripts for an array.

In this section we implement this five times, in slightly different ways, but the usage is similar:

BoundArr<int> ba(10,30); for(int i = ba.low(); i <= ba.high(); ++i) ba.at(i) = i + 1; int n = ba.at(20);
The objects are constructed giving both a lower and an upper bound, and subscripts must be in that range, inclusive. Subscripting is done with the at function, which can be used on either side of the assignment. All the versions use the same internal data structure, which is just a normal, dynamically-allocated array of the needed size. The at method just maps user subscripts to the zero-based ones by subtracting the lower bound. For instance, if we declare BoundArr<int> fred(5,10);, the object fred looks something like this:

If I call fred.at(7), the at method takes its parameter and subtracts the object value low to get the private subscript. So the data the user thinks is in position seven is in position two of the allocated C++ array. The at method also checks bounds.
The array space is dynamically allocated by the constructor and referenced by a smart pointer which frees the space when the object is destroyed.

Miscellaneous New Stuff

The example is constructed to illustrate the copying problem, but there are a few things in the code that we have not seen before which are worth mentioning.
One oddity is the placement of method bodies after the class, but in the same file. The syntax of the provided bodies is much like what we've seen when providing an implementation file. But this is a template class, so the bodies must be in the header with the template. Putting them afterwords is by no means required, but it arguably makes the code easier to read by separating the class declaration from the more complicated method bodies.
The declaration of the at method may seem strange as well. The declarations are not long:
T &at(int subs) { return m_space[offset(subs)]; } T const &at(int subs) const { return m_space[offset(subs)] }
The & at the left is part of the return type and declares the the function returns a reference. This allows the at method to be used on the left side of an assignment statement. Using the returned reference to m_space[offset(subs)] on the left of an assignment is the same as using m_space[offset(subs)] on the left of an assignment, so a.at(i) = 10 assigns to the appropriate position within m_space.
Another issue here is the overloading. There are two versions of at, but you notice that they each take a single integer parameter, which would seem to create an ambiguity. It happens, however, that C++ includes the const qualifier as part of the signature, which is why the two definitions are allowed. When the compiler encounters x.at(i), it chooses which at to call based on the presence or absence of a const qualifier on the declaration of x. If there is none, it uses the first at, otherwise the second. So, if x is created by a usual declaration like BoundArray<std::string> x, then x.at(i) uses the first at; if x is const, for instance a parameter declared const BoundArray<std::string> & x, then x.at(i) calls the second at. This is important for enforcing const, since using at on the left of an assignment is allowed only for the first form. Believe it or not, this is a common pattern for building containers.
Another novelty appears at the bottom of the header file, the declaration of the special function operator<<:
template <typename T> inline std::ostream & operator<<(std::ostream &strm, const BoundArr<T> &arr) { arr.print(strm); return strm; }
It allows BoundArr objects to be printed using the iostream facility. The parameter type std::ostream is the type (actually a super-type) of std::cout. When the compiler encounters std::cout << arr where arr is a BoundArr object, the compiler translates that as operator<<(std::cout, arr) which runs the function body just as written, being mostly the call arr.print(cout). As you can see earlier in the file, print is an ordinary object method which does just what it's name says.
The return value allows for chaining. The expression
std::cout << "The result values are: " << arr << std::endl;
uses the << operator which groups left to right, so it is equivalent to
((std::cout << "The result values are: ") << arr) << std::endl;
Which then translates to
operator<<(operator<<(operator<<(std::cout, "The result values are: "), arr), std::endl)
By returning a reference to the stream, each call to operator<< can do its work then pass the stream on to the next call.