STL question

Rob Wehrli rwehrli@azpower.com
Fri, 09 Mar 2001 21:58:26 -0700


Lucas Vogel wrote:
> 
> If I needed to create a dynamic array of objects(where I don't have a set
> number of elements set), what would be the best way to go about implementing
> this? My guess was to have a list of vectors using the STL, but I'd like to
> know of any other ways to do this. Plus, I like seeing traffic on the
> plug-devel list, so shoot me :)

Do you need to store objects of homogeneous or heterogeneous types? 
Assuming the former, you may want to consider using any one of several
"dynarray" class implementations.  You can implement the latter by using
a "C queue" of structures containing pointers and indices into objects
and mallocing them, storing their pointers into the queue and ensuring
that you free them as you finishing dequeuing/using them...however, none
of these methods even closely approach using STL in terms of power and
capability...but for relatively finite groups where the desired
operations are minimalist, it is hard to beat "straight C" for speed and
power.  Naturally, you can simply use a java.util.Vector and
v.addElement( obj ); until you get tired of it or run out of memory! 
I'm guessing, though, that your array of objects are C++ classes--from
your mention of using STL as a possible solution.

I recommend reading Matt Austern's book, Generic Programming and the STL
when you find one at Powells.com.  Another, really good and quick read
on the topic is Breymann's "Designing Components w/ the C++ STL" ...also
from AW.  On another note, you might simply want to read up on dynamic
initialization of pointer arrays.

Here is a simple example from Mike Daconta's book C++ Pointers and
Dynamic Memory Management.  From this you should find it easy to
implement an array of pointers into memory of objects of any types. 
Note that by using C++ typelib info, you can do some fairly cool dynamic
stuff on all of those objects once you get them into an application
expected to do something with them.  Also note that as you begin
spending more time working with dynamic allocation and pointer
manipulation...it is fairly easy (and everyone does it a lot before they
learn not to!) to LEAK memory like it was raining in the jungle on Kauai
(411 inches annual rainfall!).

Take Care.

Rob!


Please excuse this rather larger posting...if anyone DOES NOT want to
see this kind of stuff in the future, let me *peacefully* know and I'll
be careful to not spam everyone with it, but just reply to the sender in
the future.

/* dyninit.cpp */
#include <iostream.h>
#include <iomanip.h>
#include <new.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

const int TESTNUM = 5;
const int STRAVG = 30;

void exhausted()
{
	cout << "Exhausted the free store." << endl;
	exit(0);
}

// get_dynamic_str
// ***************
char *get_dynamic_str()
{
	char *outstr=0, *tmp=0;
	char inchar;

	int strmax = STRAVG;
	int charcnt = 0;
	
	// new the outstr
	// You should not hard code constants, use a constant
	outstr = new char[STRAVG];
	
	while ( (inchar = getchar()) != '\n')
	{
		if (charcnt == strmax)
		{
			tmp = new char[STRAVG + strmax];
			memcpy(tmp,outstr,sizeof(char) * strmax);
			delete outstr;
			outstr = tmp;
			strmax += STRAVG;
		}
		outstr[charcnt] = inchar;
		charcnt++;
	}
	
	/* null-terminate the string */
	outstr[charcnt] = '\0';
	
	return(outstr);
}

/* ***********************************************************
     FUNCTION NAME:  get_data
     PURPOSE:  get data from the user.  initialize and allocate 
               space on the heap for a date and item string
     INPUT:  date - a character string pointer pointer to be 
                    initialized.  The pointer pointer will hold the 
                    address of a pointer in the main function.
			 item - a character string pointer pointer also to be initialized.
			 price - a float
     OUTPUT:  an integer. 1 on success, else 0.
     NOTE:    It is useful to use the return of the function for an 
              error status and at the same time have the function get 
              data for the main program. It is just this case where 
              we first encounter "pointer pointers".
     AUTHOR: MCD
    ************************************************************ */

int get_data(char **date, char **item, float *price)
{
	char cdate[80];
	
	// let's look at what is on the stack
	cout << "date is " << date << endl;
	cout << "item is " << item << endl;
	cout << "price is " << price << endl;	
	
	cout << "Enter the date: ";
	*date = get_dynamic_str();

	cout << "Enter the item: ";
	*item = get_dynamic_str();
	
	printf("Enter the price: ");
	cin >> *price;
	
	return(1);
}

/* ***********************************************************
     FUNCTION NAME:  get_scores
     PURPOSE:  get scores from the user and initialize a tests 
               array in the main function.
     INPUT:  number - an integer which is the number of scores to get.
			tests - an integer pointer pointer which holds the address 
			        of an integer pointer in the main function.
     OUTPUT:  an integer, 1 on success, else 0.
     AUTHOR: MCD
    ************************************************************ */
int get_scores(int number,int **tests)
{
	int i=0;
	
	*tests = new int[number];
	
	for (i = 0; i < number; i++)
	{
		cout << "Enter score " << i << ": ";
		cin >> (*tests)[i];
	}
	
	return(1);
}

/* ***********************************************************
     FUNCTION NAME:  main for dyninit.cpp
     PURPOSE:  pass off pointers to data retrieval routines for
"filling."
               This demonstrates one valuable use of pointer pointers.
     INPUT:  none.
     OUTPUT:  none.
     AUTHOR: MCD
    ************************************************************ */
void main()
{
	char *main_date=0, *main_item=0;
	float main_price = 0.0;
	int i=0,*test_array=0;
	
	set_new_handler(exhausted);
	
	/* we already know what the pointers hold. They all
	hold NULL because that is what we initialized
	them to. */
	
	/* PROBLEM: I want to "fill" the pointers with data but
	since I should program in a modular fashion I want a 
	separate function to do the work.  How do I get a 
	function to allocate storage and fill pointers that
	I have declared in this function? 
	ANSWER: whenever you want to modify the value of a 
	variable inside a function you PASS (COPY) THE ADDRESS to the
	function.  Do the same thing for pointers. */
	
	/* let's look at the addresses of our variables. */
	cout << "main_date is at address " << &main_date << endl;
	cout << "main_item is at address " << &main_item << endl;
	cout << "main_price is at address " << &main_price << endl;
	cout << "test_array is at address " << &test_array << endl;
	cout << endl;
	
	if (!get_data(&main_date, &main_item, &main_price))
	{
		fprintf(stderr,"main: FATAL - get_data failed!\n");
		exit(0);
	}
	
	/* let's print out the data get_data provided. */
	cout << "date: " << main_date
	     << " item: " << main_item
	     << " price: " << main_price << endl;
	cout << endl;
	
	/* let's get some scores */
	if (!get_scores(TESTNUM, &test_array))
	{
		fprintf(stderr,"main: FATAL - get_scores failed!\n");
		exit(0);
	}
	cout << endl;
	
	/* print out the scores */
	cout << "test scores: " << endl;
	for (i=0; i<TESTNUM; i++)
	{
		if (!i)
			cout << test_array[i];
		if (i != (TESTNUM - 1))
			cout << " " << test_array[i];
		else
			cout << " " << test_array[i] << endl;
	}
	
	delete main_date;
	delete main_item;
	delete test_array;
}