memError occuring when using push_back method of vector

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.


I have this method in Account.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55

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

accountArray[curUserIndex].readTransactionsIntoArray();


This is the SimpleVector Template
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
// 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
using namespace 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[](const int &);

   //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[](const int &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  
Last edited on
When you create an empty vector you set aptr to null in the constructor and inside push_back you call memError() if aptr is null.
I have to declare an empty vector in the private members of my Account.h file though and push_back does work when I use it in my other methods.
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.

1
2
3
4
    //if (aptr == 0)
    //{
    //     memError();
    //} 
Topic archived. No new replies allowed.