Array of pointers to objects

I have removed a lot of extra code in program to simplify the problem. I have a Student Class that hold a Students Name & 5 grades. The Array class is supposed to hold a collection of Student objects. With the code below I can instantiate 2 Array objects and all of the appropriate constructors / destructors are called. If I add the Copy Method then the program complies, but then crashes when run. Any idea why A2 is not destroyed properly?

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
#ifndef STUDENT_H
#define STUDENT_H

#include <iostream>
#include <cstring>

using namespace std;

class Student
	{
	public:
	  explicit	Student		(const char * = "");
			~Student	();
	protected:			
		void	LocalCopy	(const char *);

	private:
			char *		pChar;
			size_t		CharCount;
			size_t		MaxSize;
			int		Grades[5];		
	};

Student::Student(const char * p):CharCount(0), MaxSize(0), pChar(0)
	{
	cout << "Student Default Constructor Called." << endl;
	for (int i = 0; i < 5; i++)
		Grades[i] = 0;

	LocalCopy(p);
	cout << "Student Default Constructor Completed." << endl;
	}

Student::~Student()
	{
	cout << "Student Destructor Called." << endl;
	delete[] pChar;		
	cout << "Student Destructor Completed." << endl;
	}

void Student::LocalCopy (const char * p)
	{
	CharCount	= strlen (p);
	MaxSize		= CharCount;
	pChar		= new char [CharCount + 1];
	strcpy (pChar, p);		
	}

#endif 


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
#ifndef ARRAY_H
#define ARRAY_H

#include <iostream>
#include "Student.h"
#include <memory.h>

using namespace std;

class Array
	{
	public:
		       Array();							
		       ~Array();

	  Array &	Copy	(const Array &);		

	protected:
	private:
		Student *	pStudent[5];
		int		StudentCount;
		int		MaxStudents;		
		
	};

inline Array::Array()
	{
	cout << "Array Default Constructor Called." << endl;
	for (int i = 0; i < 5; i++)
		pStudent[i] = new Student;
	cout << "Array Default Constructor Completed." << endl;
	}

inline Array::~Array()
	{
	cout << "Array Destructor Called." << endl;	
		for (int i = 0; i < 5; i++)
			delete pStudent[i];
	cout << "Array Destructor Completed." << endl;
	}

inline Array & Array::Copy(const Array & A)
	{
	cout << "Copy Method Called." << endl;
	return *this = A;
	}

#endif 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <iostream>
#include "Student.h"
#include "Array.h"

using namespace std;

int main()
	{
	
	Array A1;
	Array A2;

	//A1.Copy(A2);	

	return 0;
	}


Output without calling the Copy Method
Array Default Constructor Called.
Student Default Constructor Called.
Student Default Constructor Completed.
Student Default Constructor Called.
Student Default Constructor Completed.
Student Default Constructor Called.
Student Default Constructor Completed.
Student Default Constructor Called.
Student Default Constructor Completed.
Student Default Constructor Called.
Student Default Constructor Completed.
Array Default Constructor Completed.
Array Default Constructor Called.
Student Default Constructor Called.
Student Default Constructor Completed.
Student Default Constructor Called.
Student Default Constructor Completed.
Student Default Constructor Called.
Student Default Constructor Completed.
Student Default Constructor Called.
Student Default Constructor Completed.
Student Default Constructor Called.
Student Default Constructor Completed.
Array Default Constructor Completed.
Array Destructor Called.
Student Destructor Called.
Student Destructor Completed.
Student Destructor Called.
Student Destructor Completed.
Student Destructor Called.
Student Destructor Completed.
Student Destructor Called.
Student Destructor Completed.
Student Destructor Called.
Student Destructor Completed.
Array Destructor Completed.
Array Destructor Called.
Student Destructor Called.
Student Destructor Completed.
Student Destructor Called.
Student Destructor Completed.
Student Destructor Called.
Student Destructor Completed.
Student Destructor Called.
Student Destructor Completed.
Student Destructor Called.
Student Destructor Completed.
Array Destructor Completed.
Press any key to continue . . .

Output using the Copy Method
Array Default Constructor Called.
Student Default Constructor Called.
Student Default Constructor Completed.
Student Default Constructor Called.
Student Default Constructor Completed.
Student Default Constructor Called.
Student Default Constructor Completed.
Student Default Constructor Called.
Student Default Constructor Completed.
Student Default Constructor Called.
Student Default Constructor Completed.
Array Default Constructor Completed.
Array Default Constructor Called.
Student Default Constructor Called.
Student Default Constructor Completed.
Student Default Constructor Called.
Student Default Constructor Completed.
Student Default Constructor Called.
Student Default Constructor Completed.
Student Default Constructor Called.
Student Default Constructor Completed.
Student Default Constructor Called.
Student Default Constructor Completed.
Array Default Constructor Completed.
Copy Method Called.
Array Destructor Called.
Student Destructor Called.
Student Destructor Completed.
Student Destructor Called.
Student Destructor Completed.
Student Destructor Called.
Student Destructor Completed.
Student Destructor Called.
Student Destructor Completed.
Student Destructor Called.
Student Destructor Completed.
Array Destructor Completed.
Array Destructor Called.
Student Destructor Called. //At this point I get the error that Lab6.exe has stopped working.
Press any key to continue . . .



bad copying semantics.

1
2
3
4
5
inline Array & Array::Copy(const Array & A)
    {
    cout << "Copy Method Called." << endl;
    return *this = A;
    }


That code would make the the student pointers Student * pStudent[5]; the same for both the Arrays.

Which means that when one of the Arrays destructor is called, it will trash the student pointers:
1
2
3
4
5
6
7
inline Array::~Array()
    {
    cout << "Array Destructor Called." << endl;    
        for (int i = 0; i < 5; i++)
            delete pStudent[i];
    cout << "Array Destructor Completed." << endl;
    }


which means the other Array will crash when it's destructor is called and it tries to delete the student pointers, because it has already been done.
Ok, that makes sense, but how to work around it. Everything I consider winds up with the same problem. I think that I need to use a copy Student object method in the Student class and then run through a loop in the Array class calling the copy method. Am I on the right track or is there a better method?
In C++ classes, the general idea is to use the copy constructor and assignment operator for dealing
with transferring or copying data from one object to another - rather than member functions such
as the Copy function you are using for your Array class.

When dealing with classes that contain pointers that will be used for dynamic data purposes, then you need to provide your own copy constructor and assignment operators that make sure that copying is done fully rather than rely on the default constructors that would be provided by the compiler.

As we are dealing with classes and therefore C++ - I would suggest that for the Student class - the member pChar should be made a string.
and the array of students in the Array class could be handles by a vector.
This would greatly simplify the handling of copying one class to another as string and vector class would handle all the dynamic stuff for us.
I did basically what you said and after going back and re-reading the project instructions, that was what was intended. So instead of pChar to hold the StudentName, I used a custom string class that we had previously built. I also changed the int Grades[5] to use an Array Template we had previously built. And finally, in main, I used the Array template to hold the collection of Student objects. Each class handled things the way they should and the program is working. Even turned in ahead of the deadline. Thanks for your guidance!
Topic archived. No new replies allowed.