I'm actually using a SimpleVector template from a book (I modified it to include a push_back method). I have a SimpleVector of transaction arrays as a member of a class. I declared it like this as a member of my Account class
SimpleVector<Transaction>transactionVector;
I have noticed that declaring a vector like this in a function and then trying to push_back onto it results in the same kind of error
When I try to use this method to read from a text file into a SimpleVector, I get the error. I stepped it through the debugger and the error occurs when I try to use push_back.
void Account::readTransactionsIntoArray()
{
ifstream transactionFile;
transactionFileName = generateTransactionFileName();
transactionFile.open(transactionFileName);
//only try to read transactions into array if the file exists
//otherwise do nothing
if (transactionFile.good())
{
//set static variable in Transaction so that --------------------------------------------------------------------
Transaction::setTransactionIdIncrementor(transactionArray.size());
//This needs to be a char array rather than a string so it will work
//with conversion functions atoi and atof which are needed to set the Id
//number and amount. buffer temporarily holds a data
//item read from transactionFile.
char buffer[50];
//using this instead of buffer when setting value of strings in account
//so that I won't have to convert from charArray to string
string tempString;
Transaction tempTransaction; //holder for transaction data before it is pushed back onto the transactionArray vector
while(transactionFile.good())
{
transactionFile >> buffer;
tempTransaction.setTransactionId(atoi(buffer));
transactionFile >> tempString;
tempTransaction.setTransactionType(tempString);
transactionFile >> buffer;
tempTransaction.setTransactionAmount(atof(buffer));
transactionFile >> tempString;
tempTransaction.setDate(tempString);
//add the temporary Transaction object to the vector
//and if the loop starts again, new data will be put
//in tempTransaction
transactionArray.push_back(tempTransaction);
}
}
else
{
transactionFile.close();
}
}
And I'm calling it like this from a method in another class
// SimpleVector class template
#ifndef SIMPLEVECTOR_H
#define SIMPLEVECTOR_H
#include <iostream>
#include <new> // Needed for bad_alloc exception
#include <cstdlib> // Needed for the exit function
usingnamespace std;
template <class T>
class SimpleVector
{
private:
T *aptr; // To point to the allocated array
int arraySize; // Number of elements in the array
void memError(); // Handles memory allocation errors
void subError(); // Handles subscripts out of range
//int back; // holds index of last array element
public:
// Default constructor
SimpleVector()
{ aptr = 0; arraySize = 0;}
// Constructor declaration
SimpleVector(int);
// Copy constructor declaration
SimpleVector(const SimpleVector &);
// Destructor declaration
~SimpleVector();
// Accessor to return the array size
int size() const
{ return arraySize; }
// Accessor to return a specific element
T getElementAt(int position);
// Overloaded [] operator declaration
T &operator[](constint &);
//calling paramater dataItem instead of value (like in the stl vector) so that
//in comments I won't have to say weird things like "the value of value"
void push_back(T dataItem);
};
//***********************************************************
// Constructor for SimpleVector class. Sets the size of the *
// array and allocates memory for it. *
//***********************************************************
template <class T>
SimpleVector<T>::SimpleVector(int s)
{
arraySize = s;
// Allocate memory for the array.
try
{
aptr = new T [s];
}
catch (bad_alloc)
{
memError();
}
// Initialize the array.
//This code is causing problems with making a vector of acounts
//because an account object can't be set to zero
//for (int count = 0; count < arraySize; count++)
// *(aptr + count) = 0;
}
//*******************************************
// Copy Constructor for SimpleVector class. *
//*******************************************
template <class T>
SimpleVector<T>::SimpleVector(const SimpleVector &obj)
{
// Copy the array size.
arraySize = obj.arraySize;
// Allocate memory for the array.
aptr = new T [arraySize];
if (aptr == 0)
memError();
// Copy the elements of obj's array.
for(int count = 0; count < arraySize; count++)
*(aptr + count) = *(obj.aptr + count);
}
//**************************************
// Destructor for SimpleVector class. *
//**************************************
template <class T>
SimpleVector<T>::~SimpleVector()
{
if (arraySize > 0)
delete [] aptr;
}
//*******************************************************
// memError function. Displays an error message and *
// terminates the program when memory allocation fails. *
//*******************************************************
template <class T>
void SimpleVector<T>::memError()
{
cout << "ERROR:Cannot allocate memory.\n";
exit(EXIT_FAILURE);
}
//***********************************************************
// subError function. Displays an error message and *
// terminates the program when a subscript is out of range. *
//***********************************************************
template <class T>
void SimpleVector<T>::subError()
{
cout << "ERROR: Subscript out of range.\n";
exit(EXIT_FAILURE);
}
//*******************************************************
// getElementAt function. The argument is a subscript. *
// This function returns the value stored at the sub- *
// cript in the array. *
//*******************************************************
template <class T>
T SimpleVector<T>::getElementAt(int sub)
{
if (sub < 0 || sub >= arraySize)
subError();
return aptr[sub];
}
//*******************************************************
// Overloaded [] operator. The argument is a subscript. *
// This function returns a reference to the element *
// in the array indexed by the subscript. *
//*******************************************************
template <class T>
T &SimpleVector<T>::operator[](constint &sub)
{
if (sub < 0 || sub >= arraySize)
subError();
return aptr[sub];
}
template <class T>
void SimpleVector<T>::push_back(T dataItem)
{
// Copy the array size and add 1 to hold the new element
int newArraySize = this->arraySize + 1;
T* newTempArrayPtr;
// Allocate memory for the new array.
newTempArrayPtr = new T [newArraySize];
if (aptr == 0)
{
memError();
}
//copy elements of original array to new temporary array
for (int i = 0; i < arraySize; i++)
{
newTempArrayPtr[i] = aptr[i];
}
//set value in last index of newTempArrayPtr to be value of dataItem
newTempArrayPtr[newArraySize - 1] = dataItem;
//change SimpleVector's member variable arraySize to be the size of the new array
arraySize = newArraySize;
//make aptr point to address of the array that newTempArrayPtr points to
aptr = newTempArrayPtr;
}
#endif
Creating an empty vector makes sense. What's not so clear is why you check if aptr is null at that location in the code. Did you intend to check newTempArrayPtr? In C++ an exception is thrown if new fails to allocate the memory so in that case you will have to use a try-catch statement, like you do on line 65-72.
Ok thanks, I didn't think to check the push_back method. I guess I was just imitating the copy constructor without really understanding what I was doing. Now I commented out this and it seems to be working.