I l@ve RuBoard Previous Section Next Section

2.4 Using Local Static Objects

Our fibon_seq() function of Section 2.2 calculates a Fibonacci sequence of a user-specified size with each invocation, returning a vector holding the elements. That is a bit more work than is necessary.

We really need only one Fibonacci sequence vector. The elements, after all, are invariant. The only thing that changes from one call of fibon_seq() to the next is the number of elements the user wishes to have available. Consider the following three invocations of fibon_seq():



fibon_seq( 24 ); 


fibon_seq( 8 ); 


fibon_seq( 18 ); 

The first call calculates all the values necessary to fulfill the request of the second and third invocations. If a fourth invocation requested 32 elements, we really need calculate only elements 25 through 32 ?if we could cache the elements calculated between invocations. How might we do that?

A vector object local to the function does not provide a solution. The local object is created with each invocation of the function and is discarded as soon as the function terminates. A tempting alternative is to define a vector object at file scope. It is always tempting to introduce an object at file scope to solve a communications problem between functions. In general, however, file scope objects complicate the independence and understandability of individual functions.

An alternative solution, in this case, is a local static object. For example,



const vector<int>* 


fibon_seq( int size ) 


{ 


   static vector< int > elems; 


   // do the logic to populate it ... 





   return &elems; 


} 

elems is now defined as a local static object of fibon_seq(). What does this mean? Unlike a nonstatic local object, the memory associated with a static local object persists across function invocations. elems is no longer destroyed and re-created with each invocation of fibon_seq(). This is why we can now safely return elems's address.

A local static object allows us to define a single vector to hold the elements of the Fibonacci sequence. With each invocation of fibon_seq(), we need calculate only those elements that are not as yet inserted into elems. Here is one possible implementation:



const vector<int>* 


fibon_seq( int size ) 


{ 


   const int max_size = 1024; 


   static vector< int > elems; 





   if ( size <= 0 || size > max_size ){ 


        cerr << "fibon_seq(): oops: invalid size: " 


             << size << " -- can't fulfill request.\n"; 


        return 0; 


   } 





   // if size is equal to or greater than elems.size(), 


   // no calculations are necessary ... 


   for ( int ix = elems.size(); ix < size; ++ix ){ 


        if ( ix == 0 || ix == 1 ) 


             elems.push_back( 1 ); 


        else elems.push_back( elems[ix-1]+elems[ix-2] ); 


   } 


   return &elems; 


} 

Previously, we have always defined a vector to be of a particular size and have assigned values to existing elements. But in this version of fibon_seq(), we have no way of guessing how big a vector we'll need. Rather, we define elems to be an empty vector and insert elements as we need them. push_back() inserts the value at the back of the vector. The memory to support this is managed automatically by the vector class itself. (In Chapter 3 we look in detail at vectors and the other standard library container classes.)

    I l@ve RuBoard Previous Section Next Section