Solution to Assignment V

Solution by Conchung He.
-----------------------

Common errors in submissions to assignment V:

1. In indexing method, which takes an integer as parameter and retrieves
the element at that position in array, students very often forget to check
if the index is valid. Given that C++ does not provide index checking by
default, one of the points of defining your own index method is to make
it into a safe operation.

2. In insertion method, which expands the array size when the array is full,
students correctly call "new" to allocate memory to hold new contents, but
often forget to discard the old contents, which causes memory leaks.

//------------------------------------
         Sources.
//------------------------------------


#include 
#include 
#include 

template  class XArray;

// Define template of iterator for XArray
template 
class XArray_iterator
{
private:
	int index;		// Index of next element in XArray
	XArray * pArray;	// Pointer to associated XArray object

public:
	// constructor
	XArray_iterator (XArray & xa)
	{
 	  index = 0;
	  pArray = new XArray(xa); // Make a copy of xa. If we just save 
                                      // the pointer, it might  cause clash
                                      // whenever xa is destroyed but iterator
                                      // is not  notified.
                                      // Note that modifying an object over
                                      // which an iteration is taking place is
                                      // asking for trouble!

		assert(pArray); // Make sure pArray is valid
	};

	// destructor
	~XArray_iterator()
	{
	   if (pArray){
		delete pArray;
		pArray = NULL;
	    }
	};

	// Retrieve the next element
	T next ()
	{
	   assert(index < pArray->size());
	   T temp = (*pArray)[index];
	   index++;
	
   	   return temp;
	};

	// Returns true if the iteration has more elements
	bool hasNext()
	{
		return (index < pArray->size())?true:false;
	};

	// Reset the index to 0
	// To check if iterator is affected by XArray size growing.
	void reset()
	{
		index = 0;
	};
};

// Template definition
template  class XArray
{
private:
	T*  contents;  // Pointer to the Array that holds contents
	int iSize;     // Size of the XArray
	int iCurrent;  // Current length of the XArray

public:
	XArray(int size = 8);	// Constructor. Set default size of XArray as 8
	XArray(XArray& xa);	// Copy constructor
	~XArray();		// Destructor


	XArray& operator=(XArray &);	// Assignment
	bool operator==(XArray&);	// Equality
	bool operator!=(XArray&);	// Equality, for usage on XArray>
	T& operator [](int);			// Indexing
	void insert(T new_element);		// Insert a new element to the end of XArray

	int size() { return iCurrent;}	// Return the length of XArray
	friend ostream& operator<<(ostream&,XArray&); 
                   // Overloaded operator to output streams
	XArray_iterator* iterator();	// Return an iterator of XArray

	void Print();		// Print all the elements of XArray
	void Print_odd();	// Print the elements at the odd position of XArray
};

// Constructor
// initialization of the XArray
// that can hold up to iSize elements of type T

template 
   XArray::XArray(int size)
{
	assert( size > 0 );

	iSize = size;
	iCurrent = 0;
	contents = new T[size];
	assert (contents); // Make sure contents is valid
}

// Copy constructor
// Copy contents from a current XArray to a new XArray
// iSize is the current size

template 
   XArray::XArray(XArray& xa)
{
	iSize = xa.size();
	iCurrent = iSize;
	contents = new T[iSize];
	assert(contents);	// Make sure contents is valid
	for(int i=0; i
   XArray::~XArray(){
	delete[] contents;
}

// Define XArray assignment
template 
   XArray& XArray::operator=(XArray& xa)
{
	//beaware of self-assignment
	if(this == &xa)
		return *this;

	//discard old value
	delete[] contents;

	//reset the size
	iSize = xa.size();

	//reallocate new memory
	contents = new T[iSize];
	assert(contents); // Make sure contents is valid

	//copy in new elements
	for(int i=0;i
   void XArray::insert(T new_element)
{
	//ordinary situation, room for growth. 
	if (iCurrent
   T& XArray::operator[](int index)
{
	assert(index >= 0 && index < iCurrent);
	return contents[index];
}

// Equality method
template 
   bool XArray::operator==(XArray& xa)
{
	//beware of self-equality
	if(this == &xa)
		return true;

	// current sizes must be equal
	if (iCurrent == xa.size()){
		for (int i=0; i
   bool XArray::operator!=(XArray& xa)
{
	return !(*this == xa);
}

// Overload the << operator, so it can be
// used to output the contents of the XArray
template
   ostream& operator<<(ostream& out, XArray& xa)
{
	for(int i=0; i
   XArray_iterator* XArray::iterator()
{
	return (new XArray_iterator(*this));
}

// Use iterator to print all elements in odd positions
template 
void XArray::Print_odd()
{
	cout<<"Print elements in odd position: \n";
	XArray_iterator my_Iterator(*this);

	while(my_Iterator.hasNext()){
		my_Iterator.next();
		if (my_Iterator.hasNext())
			cout<
   void XArray::Print()
{
	cout<<"...Print XArray...(size="<0 && i%10 == 0) // Print ten elements on a line
			cout<<"\n";
	=09
		cout< 
//-------------------------------------------

void testINTArray()
{
	typedef XArray INTARRAY;

	cout<<"******************************\n";
	cout<<"***     Test XArray   ***\n";
	cout<<"******************************\n";

	INTARRAY intArray1(4);
	INTARRAY intArray2(4);
	INTARRAY intArray3(4);
	INTARRAY intArray4(6);

	for(int i=0;i<4;i++){
		intArray1.insert(i);
		intArray2.insert(i);
		intArray3.insert(i+1);
	}
	for(i=0;i<6;i++)
		intArray4.insert(i);

	cout<<"\n--- Test equality\n";
	cout<<"Compare XArray:\n";
	intArray1.Print();
	cout<<"With XArray:\n";
	intArray2.Print();
	if(intArray1 == intArray2)
		cout<<"Result: TRUE\n";
	else
		cout<<"Result: FALSE\n";

	cout<<"\nCompare XArray:\n";
	intArray1.Print();
	cout<<"With XArray:\n";
	intArray3.Print();
	if(intArray1 == intArray3)
		cout<<"Result: TRUE\n";
	else
		cout<<"Result: FALSE\n";

	cout<<"\nCompare XArray:\n";
	intArray1.Print();
	cout<<"With XArray:\n";
	intArray4.Print();
	if(intArray1 == intArray4)
		cout<<"Result: TRUE\n";
	else
		cout<<"Result: FALSE\n";

	cout<<"\n--- Test Indexing\n";
	cout<<"Array:\n";
	intArray1.Print();
	cout<<"Retrieve Array[2]:\n";
	cout<* pIt = intArray2.iterator();
	assert(pIt); // Make sure pIt is valid

	cout<<"Use iterator to print out all elements:\n";
	while(pIt->hasNext())
		cout<next()<<"\t";
	cout<<"\n";

	intArray2.insert(6);
	intArray2.insert(7);
	cout<<"After insertion:\n";
	intArray2.Print();
	cout<<"Use iterator to print out all elements:\n";
	pIt->reset();
	while(pIt->hasNext())
		cout<next()<<"\t";
	cout<<"\n";
	delete pIt;

}

// To test XArray class

void testLONGArray()
{
	typedef XArray DOUBLEARRAY;

	cout<<"******************************\n";
	cout<<"***   Test XArray  ***\n";
	cout<<"******************************\n";

	DOUBLEARRAY dArray1(4);
	DOUBLEARRAY dArray2(4);
	DOUBLEARRAY dArray3(4);
	DOUBLEARRAY dArray4(6);

	for(int i=0;i<4;i++){
		dArray1.insert((double)(i*1.1));
		dArray2.insert((double)(i*1.1));
		dArray3.insert((double)(i*1.1+1.1));
	}
	for(i=0;i<6;i++)
		dArray4.insert((double)(i*1.1));

	cout<<"\n--- Test equality\n";
	cout<<"Compare XArray:\n";
	dArray1.Print();
	cout<<"With XArray:\n";
	dArray2.Print();
	if(dArray1 == dArray2)
		cout<<"Result: TRUE\n";
	else
		cout<<"Result: FALSE\n";

	cout<<"\nCompare XArray:\n";
	dArray1.Print();
	cout<<"With XArray:\n";
	dArray3.Print();
	if(dArray1 == dArray3)
		cout<<"Result: TRUE\n";
	else
		cout<<"Result: FALSE\n";

	cout<<"\nCompare XArray:\n";
	dArray1.Print();
	cout<<"With XArray:\n";
	dArray4.Print();
	if(dArray1 == dArray4)
		cout<<"Result: TRUE\n";
	else
		cout<<"Result: FALSE\n";

	cout<<"\n--- Test Indexing\n";
	cout<<"Array:\n";
	dArray1.Print();
	cout<<"Retrieve Array[2]:\n";
	cout<> class
void testXArrayOnXArray()
{
	typedef XArray INTARRAY;

	cout<<"******************************\n";
	cout<<"***Test XArray>***\n";
	cout<<"******************************\n";

	INTARRAY intArray1(4);
	INTARRAY intArray2(4);
	INTARRAY intArray3(4);
	INTARRAY intArray4(6);

	for(int i=0;i<4;i++){
		intArray1.insert(i);
		intArray2.insert(i);
		intArray3.insert(i+1);
	}
	for(i=0;i<6;i++)
		intArray4.insert(i);

	XArray superArray1(2);
	XArray superArray2(2);
	XArray superArray3(3);

	superArray1.insert(intArray1);
	superArray1.insert(intArray2);

	superArray2.insert(intArray1);
	superArray2.insert(intArray3);

	superArray3.insert(intArray1);
	superArray3.insert(intArray3);
	superArray3.insert(intArray4);

	cout<<"\n--- Test equality\n";
	cout<<"Compare XArray:\n";
	superArray1.Print();
	cout<<"With XArray:\n";
	superArray2.Print();
	if(superArray1 == superArray2)
		cout<<"Result: TRUE\n";
	else
		cout<<"Result: FALSE\n";

	cout<<"\n--- Test Indexing\n";
	cout<<"Array:\n";
	superArray2.Print();
	cout<<"Retrieve Array[1]:\n";
	cout<   ***
******************************

--- Test equality
Compare XArray:
...Print XArray...(size=4)
0	1	2	3	
With XArray:
...Print XArray...(size=4)
0	1	2	3	
Result: TRUE

Compare XArray:
...Print XArray...(size=4)
0	1	2	3	
With XArray:
...Print XArray...(size=4)
1	2	3	4	
Result: FALSE

Compare XArray:
...Print XArray...(size=4)
0	1	2	3	
With XArray:
...Print XArray...(size=6)
0	1	2	3	4	5	
Result: FALSE

--- Test Indexing
Array:
...Print XArray...(size=4)
0	1	2	3	
Retrieve Array[2]:
2

--- Test Assignment
Array:
...Print XArray...(size=4)
0	1	2	3	
After Assignment:
...Print XArray...(size=6)
0	1	2	3	4	5	

--- Test Iterator
Array:
...Print XArray...(size=6)
0	1	2	3	4	5	
Use iterator to print odd elements:
Print elements in odd position: 
1	3	5	

--- Test Insertion which causes size growing
Before Insertion:
...Print XArray...(size=4)
0	1	2	3	
After Insertion:
...Print XArray...(size=8)
0	1	2	3	4	

--- Test Iterator in the case that an insertion causes size growing
Before Insertion:
Array:
...Print XArray...(size=6)
0	1	2	3	4	5	
Use iterator to print out all elements:
0	1	2	3	4	5	
After insertion:
...Print XArray...(size=12)
0	1	2	3	4	5	6	7	
Use iterator to print out all elements:
0	1	2	3	4	5	


******************************
***   Test XArray  ***
******************************

--- Test equality
Compare XArray:
...Print XArray...(size=4)
0	1.1	2.2	3.3	
With XArray:
...Print XArray...(size=4)
0	1.1	2.2	3.3	
Result: TRUE

Compare XArray:
...Print XArray...(size=4)
0	1.1	2.2	3.3	
With XArray:
...Print XArray...(size=4)
1.1	2.2	3.3	4.4	
Result: FALSE

Compare XArray:
...Print XArray...(size=4)
0	1.1	2.2	3.3	
With XArray:
...Print XArray...(size=6)
0	1.1	2.2	3.3	4.4	5.5	
Result: FALSE

--- Test Indexing
Array:
...Print XArray...(size=4)
0	1.1	2.2	3.3	
Retrieve Array[2]:
2.2

--- Test Assignment
Array:
...Print XArray...(size=4)
0	1.1	2.2	3.3	
After Assignment:
...Print XArray...(size=6)
0	1.1	2.2	3.3	4.4	5.5	

--- Test Iterator
Array:
...Print XArray...(size=6)
0	1.1	2.2	3.3	4.4	5.5	
Use iterator to print odd elements:
Print elements in odd position: 
1.1	3.3	5.5	

--- Test Insertion which causes size growing
Before Insertion:
...Print XArray...(size=4)
0	1.1	2.2	3.3	
After Insertion:
...Print XArray...(size=8)
0	1.1	2.2	3.3	4.4	


******************************
***Test XArray>***
******************************

--- Test equality
Compare XArray:
...Print XArray...(size=2)
[0] 0
[1] 1
[2] 2
[3] 3
	[0] 0
[1] 1
[2] 2
[3] 3
	
With XArray:
...Print XArray...(size=2)
[0] 0
[1] 1
[2] 2
[3] 3
	[0] 1
[1] 2
[2] 3
[3] 4
	
Result: FALSE

--- Test Indexing
Array:
...Print XArray...(size=2)
[0] 0
[1] 1
[2] 2
[3] 3
	[0] 1
[1] 2
[2] 3
[3] 4
	
Retrieve Array[1]:
[0] 1
[1] 2
[2] 3
[3] 4


--- Test Assignment
Array:
...Print XArray...(size=2)
[0] 0
[1] 1
[2] 2
[3] 3
	[0] 0
[1] 1
[2] 2
[3] 3
	
After Assignment:
...Print XArray...(size=2)
[0] 0
[1] 1
[2] 2
[3] 3
	[0] 1
[1] 2
[2] 3
[3] 4
	

--- Test Iterator
Array:
...Print XArray...(size=3)
[0] 0
[1] 1
[2] 2
[3] 3
	[0] 1
[1] 2
[2] 3
[3] 4
	[0] 0
[1] 1
[2] 2
[3] 3
[4] 4
[5] 5
	
Use iterator to print odd elements:
Print elements in odd position: 
[0] 1
[1] 2
[2] 3
[3] 4
	

--- Test Insertion which causes size growing
Before Insertion:
...Print XArray...(size=2)
[0] 0
[1] 1
[2] 2
[3] 3
	[0] 1
[1] 2
[2] 3
[3] 4
	
After Insertion:
...Print XArray...(size=4)
[0] 0
[1] 1
[2] 2
[3] 3
	[0] 1
[1] 2
[2] 3
[3] 4
	[0] 0
[1] 1
[2] 2
[3] 3
[4] 4
[5] 5
----------------------------------------------------------------------
	
Answer to part 4:
   It depends on the implemention of the iterator.
   If the iterator keeps a copy of the original XArray, it works 
   if the iterator holds a copy of the internal structure only, it doesn't.
   if the iterator holds a pointer to the object and retrieves the data 
   through the data member of the XArray, it works, and this is the prefered
   method.