Hi everyone:

I would appreciate some help with understanding how to free memory/use destructors.

I have created a 2D dynamic array template class. I'm using Xcode and Xcode keeps crashing, with the message, "out of memory." Before I implemented this array class, I was using "new" directly within main() to create my dynamic matrices and had no problems.

Two possible problems have occurred to me, and I would be very grateful for any further guidance.

1) I may not understand correctly how to use destructors (more below).
2) I am overloading () to use (i,j) for indexing within my arrays. But my destructor uses indexing, because I couldn't figure out how to use (i,j) indexing within the destructor--the destructor works like this:


template <typename T>
        Array2d<T>::~Array2d()                                                     
        {
          for(int i = 0; i < rows; i++)
	  {
		delete[ ] array[i];
	  }
	  delete[ ] array;

}

Maybe [] is not compatible with (). If it isn't, I don't know how to use () in the destructor.

When I say that I may not know correctly how to use destructors, I mean that I'm not sure HOW to call the destructor in main().

1) If arrayInstance is the name of my class instance I create in main, I have tried:

delete arrayInstance;

This produces the error: Type 'class Array2D<double>' argument given to delete expected pointer

2) I have also tried implementing the code above for my destructor within a delete function in the Array2D class:

arrayInstance.deleteArray2D();

This causes Xcode to crash with the "out of memory" message.

3) I have tried in main():

for (int i = 0; i < rows; i++)
{
delete[ ] arrayInstance[ i ];
}
delete[ ] arrayInstance;

This also causes Xcode to crash with the "out of memory" message.

Can anyone suggest what the problem might be? By the way, here is my constructor (cpp file), in case that is useful:

template <typename T>
Array2D<T>::Array2D(int rowsPub, int colsPub)
: rows(rowsPub), cols(colsPub)
{
arrayInstance = new T* [ rows ];

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

arrayInstance = new T[ cols ];
}

And I declare my data members of the class in the header:

int      rows, cols;                                                        
	T**      array;

I would like to see all of this class, well in particular the copy and assignment operator, as well as the default constructor.

The correct constructor should have:

arrayInstance = new T*[rows];
for (int i = 0; i < rows; i++)
  arrayInstance[i] = new T[cols];

the destructor should have

for (int i = 0; i < rows; i++)
  delete [] arrayInstance[i]; 
delete [] arrayInstance;

Just a quick note, you obviously don't use T** array; since you are using arrayInstance in the other parts of the code.

Finally, you can do this:

Other than that, your allocate and deallocator look ok, as long as (a) you correctly set rows, cols. (b) the memory is correctly copied, (c) any default constructor sets row and col to zero, and arrayInstance to zero.

Thanks a lot for your help, StuXYZ.

Sorry, I made a typo. My arrayInstance is T** array.

I don't have a default constructor because I thought it would be sufficient to have a constructor that takes arguments (i,j) that specify the matrix size. Am I wrong?

Regarding your end comment (b), what do you mean by, "as long as the memory is correctly copied?" Are you referring to a copy constructor? If so, I don't have one. I didn't think I would need one. Am I missing something here? Thanks for your patience!!

.h:

#include<string>
#include<iostream>
#include<vector>

using namespace std;

template <typename T>                                                         
class Array2d
{	
   int   rows, cols;       
   T**   array;    
	
public: 
         Array2d ( int rowsPub, int colsPub );  
        ~Array2d ( );
	
	void     resizeArray2d( int rowsPub, int colsPub );     
	void     deleteArray2d( );   

        // Other functions for setting values in the matrix, etc 
	
	T& operator      ( ) ( int x, int y );  
	const T& operator( ) ( int x, int y ) const;
}

.cpp

#include "Array2d.h"
#include <stdlib.h>
#include <iostream>
#include <iomanip>
#include <cmath>
#include <new>

template <typename T>
Array2d<T>::Array2d(int rowsPub, int colsPub)
: rows(rowsPub), cols(colsPub)
{	
	array = new T* [ rows ]; 
	for (int i = 0; i < rows; i++)
		array[i] = new T[ cols ];
	
	// Initialization
	for(int i = 0; i < rows; i++)
		for(int j = 0; j < cols; j++)
			array[i][j] = 0;  
}

template <typename T>
Array2d<T>::~Array2d()           
{
	for(int i = 0; i < rows; i++)
	{
		delete[ ] array[i]; 
	}
	delete[ ] array;        
}

// Functions
template <typename T>
void Matrix2d<T>::resizeArray2d(int rowsPub, int colsPub)
{
	for(int i = 0; i < rows; i++)
		delete[ ] array[i];
	delete[ ] array;
	
	array = new T * [ rows ];
		for(int i = 0; i < rows; i++)
			array[i] = new T[ cols ];
}


template <typename T>
T& Array2d<T>::operator() (int x, int y)
{
	if(x > rows || x < 0 || y > cols || y < 0)
		
		cout << "Error! Enter correct dimensions ";
	
	else
		
		return array[x][y];                     
}   

template <typename T>
const T& Array2d<T>::operator() (int x, int y) const 
{
	if(x > rows || x < 0 || y > cols || y < 0)
		
		cout << "Error! Enter correct dimensions ";
	
	else
		
		return array[x][y];                    			
}

template class Array2d<int>;
template class Array2d<double>;
template class Array2d<long>;

The mistake is almost certainly with the copy and assignment operators. You will get both, auto written by the compiler if you don't provide them. In this class both will be 100% wrong, as they do a shallow copy.

So either, prove that they don't get called: E.g adding

private:

Array2d(const Array2d<T>&);
Array2d<T>& operator=(const Array2d<T>&);

In the private section of your class declaration.

Alternatively, write a copy/assignment operator.

Additional:

Check what happens if you do actually call it with integer values ==0;

Thank you very much StuXYZ. I was not aware of this. I must stop for the day, but I will write a copy/assignment operator tomorrow.

Hi StuXYZ:

I tried implementing copy/assignment operators by adding the code below to my header and .cpp files, but I'm still getting Xcode crashes.

Would you mind taking a look at my code and commenting about any problems? I may have made some silly mistakes because I'm not sure I understand copy/assignment operators as well as I should. I

.h file:

Array2d ( const Array2d<T>& m );          //copy constructor
Array2d<T>& operator=( const Array2d<T>& m );   //copy assignment

.cpp file:

template <typename T>
Array2d<T>::Array2d(const Array2d<T>& m)       
: rows(m.rows), cols(m.cols)
{
	array = new T* [ rows ]; 
	for (int i = 0; i < rows; i++)
	{
		array[i] = new T[ cols ];
	}
	for (int i = 0; i < rows; i++)
	{
		for(int j = 0; j < cols; j++)
		{
			array[i][j] = m.array[i][j];
		}
	}
}

template <typename T>
Array2d<T> &Array2d<T>::operator=(const Array2d<T>& m) 
{ 
	if (this == &m) 
	{
		return *this; 
	} 
	else 
	{
		if (rows != m.rows || cols != m.cols) 
		{ 
			this->~Array2d(); rows = m.rows; cols = m.cols; 
			array = new T* [ rows ]; 
			
			for (int i = 0; i < rows; i++)
			{
				array[i] = new T[ cols ];
			}
			
		}
	}
	for (int i = 0; i < rows; i++) 
	{ 
		for (int j = 0; j < cols; j++) 
		{
			array[i][j] = m.array[i][j];
		}
	}
	return *this;
}

The copy constructor looks ok, with the exception that you must put a guard in for rows==0 and cols==0, but the assignment operator is a mess.

The problem is is that if you reassign memory you haven't deleted the old memory.
In particular you call the delete operator directly from the class, this is almost always a serious error.

This is much more likely to work.

template <typename T>
Array2d<T>&
Array2d<T>::operator=(const Array2d<T>& m) 
{ 
  if (this != &m) 
    {
       if (rows != m.rows || cols != m.cols) 
	 {
            for(int i=0;i<rows;i++)
              delete [] array[i];
            delete [] array;
            
            // Essentual in case m.cols or m.rows ==0
            array=(m.rows) ? new T*[m.rows] : 0;
            for(int i=0;i<m.rows;i++)
               array[i]=(m.cols) ? new T[m.cols] : 0;
            rows=m.rows;
            cols=m.cols;
          }

	for (int i = 0; i < rows; i++)  
          for (int j = 0; j < cols; j++) 
             array[i][j] = m.array[i][j];
    }
  return *this;
}

Also finally make sure that your default constructor is like this:

template<typename T>
Array2d<T>::Arra2d() : rows(0),cols(0),array(0) {}

or your delete operator will cause a problem.

Also I really think you should add a std::cout<<"rows == "<<rows<<" cols=="<<cols<<std::endl; to your destructor.

Edited 6 Years Ago by StuXYZ: n/a

Thanks a lot for your help, StuXYZ. Unfortunately, Xcode is still crashing though! Although the error is now "uncaught exception." If you do have any further suggestions, I would love to hear them if you have time.

Thanks again!

It seems like it is actually some other part of your code now. You could run your code in the debugger. If you can write a simple test case for array2d, then post the whole code here. [At the moment, we have nothing that we can actually run.]


You can also put a simple try { // your code here } catch (std::exception& A) { std::cout<<"Exception == "<<A.what()<<std::endl; } , around the code in int main(). [Assuming that you are not using throw in your array2d code.]

This article has been dead for over six months. Start a new discussion instead.