Back to July Calendar

Previous Entry Next Entry→

September 30, 2005

"The 'Otherizing' of women is the oldest oppression known to our species, and it’s the model, the template, for all other oppressions."
--Robin Morgan (b. 1941), U.S. author, feminist, and child actor. The Word of a Woman, part 2 (1992).

"Instructing in cures, therapists always recommend that “each case be individualized.” If this advice is followed, one becomes persuaded that those means recommended in textbooks as the best, means perfectly appropriate for the template case, turn out to be completely unsuitable in individual cases."
--Anton Pavlovich Chekhov (1860–1904), Russian author, playwright. The professor in A Boring Story, Works, vol. 7, p. 298, “Nauka” (1976).  Chekhov practiced medicine throughout his life.

Microsoft wordcheck objects to "othering," whether caps or no.  It prefers "ethering."  Maybe the ladies wouldn't like that either, but surely ether is other from other.  It may be ether from other, but it's not other from ether, either.

Ok, grindstone, how about we wear you down a bit more, this being the end of September.

The next example from Deitel gets into more advanced writing and reading to/from vector memory. 

The vector constructor std::vector< int > integers( array, array + SIZE ) takes the address of the first element of the array and the address of the last element and scoops up all integer-sized pieces inclusively between these.

The line std::ostream_iterator< int > output( cout, " " ); defines an ostream_iterator called output which is a type-safe output mechanism that outputs only values of type int or a compatible type.  The first argument to the constructor specifies the output stream, and the second argument is a string specifying separator characters for the values output—in this case, a space character.

The function call std::copy( integers.begin(), integers.end(), output ) uses algorithm copy from the Standard Library to output (copy) the entire contents of vector integers to the standard output. Algorithm copy copies each element in the container starting with the location specified by the iterator in its first argument and up to—but not including—the location specified by the iterator in its second argument. The first and second arguments must satisfy input iterator requirements—they must be iterators through which values can be read from a container. Also, applying ++ to the first iterator must eventually cause the first iterator to reach the second iterator argument in the container. The elements are copied to the location specified by the output iterator (i.e., an iterator through which a value can be stored or output) specified as the last argument. In this case, the output iterator is an ostream_iterator (output) that is attached to cout, so the elements are copied to the standard output. To use the algorithms of the Standard Library, you must include the header file <algorithm>.

The successive lines, integers[ 0 ] = 7 and integers.at( 2 ) = 10  illustrate two ways to subscript through a vector (that also can be used with the deque containers).  The first uses the subscript operator that is overloaded to return either a reference to the value at the specified location or a constant reference to that value, depending on whether the container is constant. Function at performs the same operation with one additional feature—bounds checking.  Function at first checks the value supplied as an argument and determines whether it is in the bounds of the vector. If not, function at throws an out_of_bounds exception (the try function.)   Chapter 13 of Deitel focuses on Exception Handling.  Some of the more important STL exception types are in the table below.

STL exception types

Description

out_of_range
Indicates when subscript is out of range—e.g., when an invalid subscript is specified to vector member function at.
invalid_argument
Indicates an invalid argument was passed to a function.
length_error
Indicates an attempt to create too long a container, string, etc.
bad_alloc
Indicates that an attempt to allocate memory with new (or with an allocator) failed because not enough memory was available

 

An insert function is called by integers.insert( integers.begin() + 1, 22 ) which inserts the value 22 before the element at the location specified by the iterator in the first argument. In this example, the iterator is pointing to the second element of the vector, so 22 is inserted as the second element and the original second element becomes the third element of the vector. Other versions of insert allow inserting multiple copies of the same value starting at a particular position in the container, or inserting a range of values from another container (or array), starting at a particular position in the original container.

Use of the two erase functions that are available in all first-class containers is illustrated by integers.erase( integers.begin() ) and  integers.erase( integers.begin(), integers.end() ).  The first indicates that the element at the location specified by the iterator argument should be removed from the container (in this example, the element at the beginning of the vector) and the second specifies that all elements in the range starting with the location of the first argument up to—but not including—the location of the second argument should be erased from the container. In this example, all the elements are erased from the vector. Clever use of the ternary operator in (integers.empty() ? "is" : "is not" ) << " empty" then confirms that the vector is empty.

The insert function call integers.insert( integers.begin(), array, array + SIZE ) demonstrates the version of function insert that uses the second and third arguments to specify the starting location and ending location in a sequence of values (possibly from another container; in this case, from the integers array) that should be inserted into the vector. Remember that the ending location specifies the position in the sequence after the last element to be inserted; copying is performed up to—but not including—this location.

 

// Testing Standard Library vector class template
// element-manipulation functions.

#include <iostream>

using std::cout;
using std::endl;

#include <vector>    // vector class-template definition
#include <algorithm> // copy algorithm

int main()
{
   const int SIZE = 6;
   int array[ SIZE ] = { 1, 2, 3, 4, 5, 6 };

   std::vector< int > integers( array, array + SIZE );
   std::ostream_iterator< int > output( cout, " " );

   cout << "Vector integers contains: ";
   std::copy( integers.begin(), integers.end(), output );

   cout << "\nFirst element of integers: " << integers.front()
        << "\nLast element of integers: " << integers.back();

   integers[ 0 ] = 7;     // set first element to 7
   integers.at( 2 ) = 10; // set element at position 2 to 10

   // insert 22 as 2nd element
   integers.insert( integers.begin() + 1, 22 );

   cout << "\n\nContents of vector integers after changes: ";
   std::copy( integers.begin(), integers.end(), output );

   // access out-of-range element
   try {
      integers.at( 100 ) = 777;
   } // end try

   // catch out_of_range exception
   catch ( std::out_of_range outOfRange ) {
      cout << "\n\nException: " << outOfRange.what();
   } // end catch

   // erase first element
   integers.erase( integers.begin() );
   cout << "\n\nVector integers after erasing first element: ";
   std::copy( integers.begin(), integers.end(), output );
  
   // erase remaining elements
   integers.erase( integers.begin(), integers.end() );
   cout << "\nAfter erasing all elements, vector integers "
        << ( integers.empty() ? "is" : "is not" ) << " empty";

   // insert elements from array
   integers.insert( integers.begin(), array, array + SIZE );
   cout << "\n\nContents of vector integers before clear: ";
   std::copy( integers.begin(), integers.end(), output );
  
   // empty integers; clear calls erase to empty a collection
   integers.clear();
   cout << "\nAfter clear, vector integers "
        << ( integers.empty() ? "is" : "is not" ) << " empty";

   cout << endl;
  
   return 0;
} // end main

Here's the output:

Vector integers contains: 1 2 3 4 5 6
First element of integers: 1
Last element of integers: 6

Contents of vector integers after changes: 7 22 2 10 4 5 6

Exception: invalid vector<T> subscript

Vector integers after erasing first element: 22 2 10 4 5 6
After erasing all elements, vector integers is empty

Contents of vector integers before clear: 1 2 3 4 5 6
After clear, vector integers is empty

 

 

Notes about vectors:

Unlike arrays, you don't want to preallocate memory for vectors.  It is more efficient to add elements at run-time.

Some value initializations:

vector<int> fvec(10) will initialize a vector with 10 elements, each initialized to 0.
vector<string> fvec(10)
will instantiate 10 empty strings.
vector<T> fvec(gvec) will initialize a vector copy of gvec.
vector<int> fvec(n, i) will initialize a vector with n elements, each initialized to i.

Programmers new to C++ sometimes think that subscripting a vector adds elements: wrong! 

Here's a little experiment with vectors and strings:

#include <iostream>
#include
<vector>
#include
<string>
using
namespace std;

int main() {
   vector<string> svec(4);
  
//for(int i=0;i<10;++i)
  
svec.at(0) = "Hi";
  
svec.at(1) = "there";
  
svec.at(2) = "Sam";
  
svec.at(3) = "boy.";
  
for(int i=0;i<4;++i)
  
   for(string::size_type index=0;index!=svec[i].size();++index)
         svec[i][index] = toupper(svec[i][index]);

   for(int i=0;i<4;++i) cout << svec[i] << " ";
}

Produces just what you'd expect:  HI THERE SAM BOY.

The idea of the iterator being like a pointer is still a bit slippery. 

vector<float>::iterator iter = fvec.begin()  will initialize iter to the value returned by the vector operation begin().  Assuming it exists, this is the same as fvec[0].   You can dereference the iterator to obtain this value also, so *iter would then be the same as fvec[0].