How to delete 2D Array? Thanks!

Hi guys! I've absolutely no idea why my delete codes inside the destructor won't be able to functionally well. I hope u guys can help me for this.

Thank you so much!


 
Please refer to last post for updated program!Thanks!
Last edited on
What do you mean "it won't work"?

Is your application crashing?


You need to have a copy constructor that duplicates the data. Imagine:

object A: constructed --> allocates memory (via new[]for the 2D array

object B: constructed as a copy of A --> no allocation of a 2D array, instead it shares the memory for the 2D array with object A

object B: destroyed --> the 2D array is freed (via delete[])

object A: thinks its 2D array is still A-OK even though object B (which no longer exists) deleted the 2D array (so now it no longer exists either)


Whenever your objects maintain pointers to dynamically-allocated data, they must be careful to prevent these kinds of problems. In your case, I would just make a deep copy -- that is, duplicate the 2D array -- whenever you copy the Array2D object.
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
class Array2D
{
    public:
        ...
        Array2D( const Array2D& );               // copy constructor
        Array2D& operator = ( const Array2D& );  // copy assignment operator
    ...
};

/*
  copy constructor
*/
Array2D::Array2D( const Array2D& original )
{
    // Copy the original's attributes (number of rows and columns)
    row = original.row;
    col = original.col;

    // Allocate new space for our copy of the original data
    p   = new int* [row];
    for (int i=0; i < row; i++)
        p[i] = new int [col];

    // Copy the original data into our data
    for (int i = 0; i < row; i++)
    for (int j = 0; j < col; j++)
        p[i][j] = original.p[i][j];
}

/*
  copy assignment operator
*/
Array2D& Array2D::operator = ( const Array2D& original )
{
    // same stuff as above, plus the following:
    return *this;
}

These two methods (copy constructor and copy assignment operator) are part of "the Rule of Three" when programming in C++:
http://en.wikipedia.org/wiki/Rule_of_three_%28C%2B%2B_programming%29

You can make it easier on yourself by having a private method (like copy( const Array3D& ); or somesuch) and then calling that method from your copy ctor and copy assign op, which would then look like:
1
2
3
4
5
6
7
8
9
10
Array2D::Array2D( const Array2D& original )
{
    copy( original );
}

Array2D& Array2D::operator = ( const Array2D& original )
{
    copy( original );
    return *this;
}


Hope this helps.
@Duoas, I really appreciate your effort. Thanks very much!.

Actually I have the 2 functions inside my class. However, the addArray works well but the multiplyArray is failed due to the destructor.

1
2
Please refer to last post for updated program!Thanks!
}	  
Last edited on
I can't see how that function could possibly fail except for the reasons I've already stated.

If you can, post your whole code online somewhere where we can peruse it, like pastebin or somesuch.
If you try to execute the below program, you will obtain some garbage values, however, you will obtain correct result if you does not include anything inside the destructor. Thanks!


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
'#include <iostream>
#include <cstdlib>
#include <ctime>

using namespace std;

class Array2D
{
	public: 
			Array2D();
			Array2D(int, int);
			~Array2D();
			Array2D (const Array2D&);
			

			void addMatrix (const Array2D&);

			Array2D multiplyMatrix (const Array2D&);
	
			void printMatrix ();
	
	private:
			int row;
			int col;
			int **m;
			void initialize ();
			void generateArray2D ();
			
};



static int size=0;
Array2D::Array2D()
{

}


Array2D::Array2D(int rows, int cols)
{
	this -> row = rows;
	this -> col = cols;
	initialize();
	generateArray2D ();
}


Array2D::~Array2D()
{

	for (int i = 0; i < row; i++)
  	{
  		delete[]m[i];
  	}
	delete[]m;

}


Array2D::Array2D(const Array2D& mx)
{
	this -> row = mx.row;
	this -> col = mx.col;
	
  	initialize();
	
	for (int i = 0; i < row; i++)
		for (int j = 0; j < col; j++)
			m[i][j] = mx.m[i][j];
}


void Array2D::initialize()
{
	m = new int* [row];
	
	for(int i=0; i< row; i++)
		m[i] = new int[col];
}


void Array2D::generateArray2D ()
{
	for (int i = 0; i < row; i++)
		for (int j = 0; j < col; j++)
		{
			m[i][j] = rand () % 10;
		}
}




void Array2D::addMatrix (const Array2D& mx)
{
	for (int i = 0; i < row; i++)	 
		for (int j=0; j < col; j++)
			m[i][j] += mx.m[i][j];	 	       
}



Array2D Array2D::multiplyMatrix (const Array2D& mx)
{
	int rowAB = row;
	int colAB = mx.col;
	
	Array2D ab(rowAB, colAB);
	
	for(int i=0; i< row; i++)
	{

		for(int j=0; j< mx.col; j++)
		{
			int sum = 0;
			for(int k=0; k < col; k++)
			{
				sum += m[i][k] * mx.m[k][j];	    			
			}	 
			ab.m[i][j] = sum;
		}
	}
	return ab;	     
}


void Array2D::printMatrix ()
{
	for (int i = 0; i < row; i++)
	{
		cout<< "\t [";
		for (int j = 0; j < col; j++)
		{
			if(j+1 != col)
				cout  <<m[i][j] << "\t";
				
			else
				cout  <<m[i][j];
		}
		cout << "]"<< endl;
	}
}


int main()
{
	srand(time(NULL));

			int rows=2, cols=2;
			int rowsB;
			int colsB=1;
						
			rowsB = cols;	 	 	 	 
									
			cout<< "Given matrix A\n\n";	
			Array2D mxA3(rows, cols);
			mxA3.printMatrix ();
								
			cout<< "\nand Array2D B\n\n";
			Array2D mxB3(rowsB, colsB);
			mxB3.printMatrix ();
									
			cout<< "\nA * B is \n\n";
			Array2D mxAB(rows, colsB);
			mxAB = mxA3.multiplyMatrix(mxB3); 
				
			mxAB.printMatrix ();
				

} 

The problem is because you did not implement a copy assignment operator as I instructed you, so when "ab" (line 109) is destructed (line 125), it destroys "mxAB"'s memory too...

To see the difference, change lines 165 and 166 to:
165
166
			Array2D mxAB(mxA3.multiplyMatrix(mxB3));
In this case, you have a proper copy constructor implemented, so when "ab" (line 109) is destructed, it only affects itself (since "mxAB" has its own copy of the matrix data).

A few other things you should be aware of:


Line 33: static int size=0; What is this for?


Line 36: Your default constructor needs to initialize the values of your class, otherwise your destructor will crash your program with a GPF.
34
35
36
37
38
Array2D::Array2D()
{
	row = col = 0;
	m = NULL;
}
Now, when your destructor is called, make sure you don't try to delete[] anything that doesn't exist:
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
Array2D::~Array2D()
{
	if (m != NULL)
	{
		for (int i = 0; i < row; i++)
	  	{
  			delete[]m[i];
	  	}
		delete[]m;
	}

	// This isn't actually necessary in the destructor, but keep reading...
	row = col = 0;
	m = NULL;
}


When you implement your assignment operator, keep in mind that you may have to destroy existing data:
1
2
3
4
5
6
7
8
9
Array2D& Array2D::operator = ( const Array2D& a )
{
	if (m != NULL)
	{
		finalize();  // same stuff as in destructor, not forgetting the stuff = 0 statements
	}

	copy( a );  // same stuff as in the copy constructor
}
[edit] You will need to implement the finalize() and copy() methods, just like initialize() and generateArray2D() are.[/edit]

Finally, your matrix class does not make its size or contents available for inspection. You might want to add that kind of stuff:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Array2D
{
	public:
		...

		int rows()    const { return row; }
		int columns() const { return col; }

		int& index( int r, int c ) { return m[r][c]; }

	...
};

...

int main()
{
	...
	cout << "The size of matrix A is " << mxA3.rows() << " by " << mxA3.columns() << ".\n";
	...
	mxA3.index( 0, 1 ) = 42;
	...

Hope this helps.
Last edited on
Hi! Ya! It works great according to your instructions. However, I've some questions to ask:

1) If I don't have a assignment (=) operator and obtain the erroneous results is because the array mxAB just points to what mxA3 points to (line 165), it doesn't not have a deep copy of entire array, am I right?

2) Copy constructor and assignment (=) operator are also the same, right? Both of them are deep copying of entire array and If I've a copy constructor so that assignment (=) operator is not necessary as I can do like Array2D mxAB(mxA3.multiplyMatrix(mxB3));

3) How can I add in a static int variable inside the destructor function in order to keep track the rows have been deleted? So that I can call/refer to it inside my main function?
(cout cannot be placed inside the destuoctor as I don't want it to be displayed for all times)

4) I'm also give a void pointer to create a 2D array to be familiar with data type void according to my prof. For the initialization, I won't be able to define storage as above (m = new int* [row];) , so I was taught by someone to do as below, is it correct? Any constraints or problems for doing these? Thanks!

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
// I'm given a void poiter ( void***m ) instead of int **m

void Array2D::initialize()
{
	m = new void**[row];
	
	for(int i=0; i< row; i++)
		m[i] = new void*[col];
}


void Array2D::generateArray2D ()
{
	int *p;
	
	for (int i = 0; i < row; i++)
	{
		for (int j = 0; j < col; j++)
		{
			p = new int;
			*p = rand () % 10;
			m[i][j] = p;
		}
	}		
}



Thanks!
Last edited on
1) Correct.
2) Mmm, close enough.
3) What? Once you destroy the object, it no longer exists. That is, once you are done with a thing, you should not make any references to it any more. Doing so is akin to:
1
2
3
4
5
6
7
8
9
10
void fooey( int x )
{
  int y = x * 2;
}

int main()
{
  fooey( 12 );
  cout << fooey::y << endl;  // makes no sense -- fooey::y doesn't exist anymore!
}

4) Er, that's insane, but sure...
20
21
m[i][j] = (void*)new int;
*(int*)(m[i][j]) = rand() % 10;
or
20
21
m[i][j] = (void*)(new int( rand() % 10 ));
You just have to make absolutely sure you don't forget the casts when you want to get data out (and it is a good idea to have them when putting data in) -- and also that each item is a pointer that must at some point be freed.

Good luck!
@Duoas, really appreciate your efforts. Many thanks ^_^"

How long have you been learning C++?

Do you like JAVA? Why would you prefer either one of them?

Glad to be of help.

24 years.

I do not like Java, to put it mildly. [edit] I can use it proficiently, though. [/edit]
Last edited on
Topic archived. No new replies allowed.