Question

I have an assignment to create a template container class with a dynamic array that can be increased and decreased. When the array is displayed, I get either garbage numbers or no numbers at all for the elements in the array where it was expanded(so if it expanded on the fifth element, the value would turn to junk after I enter the sixth). When I try to remove elements I get a Debug Assertion Failed error.

Here is my code:

template <class T> class container {
public:
   container(); // constructor
   // Post-condition: count is set to -1 and dynamic array size set to 5
   ~container(); //destructor
   void insert(T &n);
   //  Pre-condition: a value is passed to the function 
   // Post-condition: if data array is not full, increment count by 1 and insert the value in the array 
   // Otherwise, display "Container full! No insertion is made."            
   void remove();
   //Post-condition: if data array is not empty, remove the data[count] element in data array and decrement count by 1; 
   //otherwise, display a message "Container empty! Nothing is removed from it."    
   void display();
   // Post-condition: if the array is not empty, displays all values in data array similar to the sample output;
   //Otherwise, display the message “Container is now empty!"
   void fillarray(container c);
   //pre-condition: a container c is passed to the function
   //post-condition: dynamic array of chosen type is created and filled continuously with user entered values
private:
   bool empty;
   //Post-condition: returns true is the array is empty, otherwise returns false
   T *data; // dynamically allocated array used to store or contain the inserted values
   int count;   // indicates how many values have been inserted
   int max;
};
template <class T> container<T>::container()
{
   count = -1;
   max = 5;
   data = new T[max];
   assert(data != NULL);
}
template <class T> container<T>::~container()
{
   delete [] data;
}
template <class T> void container<T>::insert(T &n)
{
   if (count >= (max - 1))
   {
      max = max * 2;
      cout << "\nContainer full! Array size is increased by " << max/2  << ".";
      T *temp = new T[max];
      assert(temp != NULL);
      for (int i = 0; i < count; i++)
         temp[i] = data[i];
      delete [] data;
      data = temp;
      count++;
      data[count] = n;
   }
   else
      count++;
   data[count] = n;
}
template <class T> void container<T>::remove()
{
   empty = count < 0;
   if (empty == 1)
   {
      cout << "\nContainer empty! Nothing is removed from it.";}
   else
   {
      count--;
      T *temp1 = new T[max];
      assert(temp1 != NULL);
      for (int i = 0; i < count; i++)
         temp1[i] = data[i];
      delete [] data;
      data = temp1;
   }
}
template <class T> void container<T>::display()
{
   empty = count < 0;
   if (empty == 1)
   {
      cout << "\nContainer is now empty!";}
   else
   {
      for (int i = 0; i <= count; ++i)
         cout << " " << data[i];
   }
}
template <class T> void container<T>::fillarray(container c)
{
   char ans;
   do
   {
      T value;
      cout << "\nEnter a value:";
      cin >> value;
      c.insert(value);
      cout << "\nAfter inserting, the \"container\" contains:" << endl;
      c.display();
      cout << "\nEnter more? (Y/y or N/n)";
      cin >> ans;
   } while (ans == 'Y' || ans == 'y');
   for (int i = 0; i <= count; i++) 
   {
      c.remove();
      cout << "\nAfter removing a value from it, the \"container\" contains:" << endl;
      c.display();
      cout << endl;
   }
}
// The main driver function to be used to test implementation
int main()
{
   char choice;
   cout << "\nEnter S for string container, D for double";
   cin >> choice;
   if (choice == 'S' || choice == 's')
   {
      container<string> c;
      c.display();
      c.fillarray(c);
   }
   else if(choice == 'D' || choice == 'd')
   {
      container<double> c;
      c.display();
      c.fillarray(c);
   }
   return 0;
}
Was it helpful?

Solution

template <class T> void container<T>::fillarray(container c)
{
    //...
}

This function actually involves two container<T> objects: *this and c.

Since you "pass by value" (the function parameter is not a reference), c in fillarray is created as a copy of the original c in main. In fillarray you modify c, which deletes and changes c.data, but this->data still contains the dangling pointer to the original storage. Before long, you get undefined behavior; luckily enough bad things happened you could tell something was wrong.

Per the Rule of Three (Plus Two), if a class has a destructor, you probably should not allow the compiler to generate the default copy constructor and copy assignment, and you may want to consider implementing a move constructor and move assignment.

The easiest, and sometimes best, way of meeting that rule is to disable copying:

template <class T> class container
{
public:
    container(container const&) = delete;
    container& operator=(container const&) = delete;
    //...
};

Then the compiler will make sure you don't accidentally make a copy and get yourself into this sort of trouble.

OTHER TIPS

You make life confusing by count referring to maximum index rather than the number of entries. Using your scheme though, this line in insert is odd:

  for (int i = 0; i < count; i++)

As that won't copy the final entry.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top