Hello fellow programmers. I am new to c++ and also fairly new to programming. I have been given an assignment to create a class called Doctor. The user inputs a number of patients and patient names for the doctor and the program prints them out along with several supporting other functions. However, I am having a problem. At the end of the run (which is correct), I receive the following error: *** glibc detected *** double free or corruption (fasttop): 0x09499008 ***. Can any one tell me what is happening? Here is my code:
#include <iostream>
#include <string>
#include <assert.h>
//#define PRODUCT_VERSION
usingnamespace std;
//Doctor class
class Doctor {
public:
//Doctor Constructor and Destructor
Doctor();
~Doctor();
//public variables
string name; //name of Doctor
int numPatients; //number of patients
string* patientList; //list of patients
//asks user to input public variables
void askUserInput();
//prints doctor's patient list and returns number of prints
//for testing purposes
int printPatients();
//resets the number of patients to zero and the patientList to an
//empty list
void reset();
//overloads the ++ operator to create a copy of the patientList
voidoperator++();
};
//make Doctor instance for testing
Doctor docLow;
Doctor docMid;
Doctor docHigh;
//make Doctor list copy
string* copyList;
int main()
{
//if defined, product version is executed with user input.
//otherwise, testing is executed with pre-defined boundary inputs
#ifdef PRODUCT_VERSION
#else
//Unit Testing
cout << "*** UNIT TESTING for Doctor class ***\n\n";
//boundary tests
int i = 0;
//tests 3 cases
while (i < 3)
{
switch (i)
{
case 0:
{
//Empty case
cout << "Testing Low Boundary...\n\n";
docLow.name = "Empty";
docLow.numPatients = 0;
docLow.patientList = new string[docLow.numPatients];
runTests(docLow);
docLow.patientList = NULL;
i++;
break;
}
case 1:
{
//Middle case
cout << "\nTesting Middle Boundary...\n\n";
docMid.name = "Medium";
docMid.numPatients = 5;
docMid.patientList = new string[docMid.numPatients];
//predefined patientList
docMid.patientList[0] = "Amanda";
docMid.patientList[1] = "Bradley";
docMid.patientList[2] = "Charlie";
docMid.patientList[3] = "Doug";
docMid.patientList[4] = "Eno";
runTests(docMid);
docMid.patientList = NULL;
i++;
break;
}
case 2:
{
//Long Case
cout << "\nTesting High Boundary...\n\n";
docHigh.name = "Long";
docHigh.numPatients = 10;
docHigh.patientList = new string[docHigh.numPatients];
//predefined patientList
docHigh.patientList[0] = "Amanda";
docHigh.patientList[1] = "Bradley";
docHigh.patientList[2] = "Charlie";
docHigh.patientList[3] = "Doug";
docHigh.patientList[4] = "Eno";
docHigh.patientList[5] = "Fran";
docHigh.patientList[6] = "Gabriel";
docHigh.patientList[7] = "Hannah";
docHigh.patientList[8] = "Ico";
docHigh.patientList[9] = "Jack";
runTests(docHigh);
docHigh.patientList = NULL;
i++;
break;
}
}
}
#endif
}
//Doctor destructor
Doctor::~Doctor()
{
numPatients = 0;
//allocated memory is deleted
delete [] patientList;
patientList = NULL;
}
void Doctor::askUserInput()
{
//Asks user for doctor name
cout << "What is the doctor's name?: " ;
getline(cin, name);
cout << endl;
//Asks user for number of patients
cout << "Enter the number of patients the doctor has: ";
cin >> numPatients;
string getEnter;
getline(cin, getEnter);
cout << endl;
//allocates memory for dynamic string
patientList = new string[numPatients];
//Asks user for each patient's name
cout << "Enter each patient's name.\n\n";
for (int i = 0; i < numPatients; i++)
{
cout << "Patient " << i + 1 << ": ";
getline(cin, patientList[i]);
cout << endl;
}
cout << endl;
}
}
void Doctor::reset()
{
//resets number of patients to zero
numPatients = 0;
//deletes allocated memory
delete [] patientList;
//makes empty list
patientList = new string[numPatients];
}
void Doctor::operator++()
{
//allocates necessary memory for a copy list
copyList = new string[numPatients];
//iterates through patientList and copies each patient to copyList
for (int i = 0; i < numPatients; i++)
{
copyList[i] = patientList[i];
}
}
bool checkEqualArrays(string array1[], string array2[], Doctor doc)
{
//iterates through both arrays and ensures they are equal
int i = 0;
bool equal = true;
while(i < doc.numPatients && equal)
{
if (array1[i] != array2[i])
{
equal = false;
}
i++;
}
//returns true if equal, false otherwise
return equal;
}
void runTests(Doctor doc)
{
//creates local copy variables in order to restore
//original values when Doctor variables are reset
string storeName;
int storeNumPatients;
string* storePatientList;
storeName = doc.name;
storeNumPatients = doc.numPatients;
storePatientList = new string[doc.numPatients];
for (int i = 0; i < storeNumPatients; i++)
{
storePatientList[i] = doc.patientList[i];
}
//prints out Doctor's public variables that were either input
//by the user (checks askUserInput()) or pre-defiend by the programmer
cout << "Test results: \n\n";
cout << "Doctor name: " << doc.name << endl << endl;
cout << "Number of Patients: " << doc.numPatients << endl << endl;
cout << "Patient List: \n\n";
for (int i = 0; i < doc.numPatients; i++)
{
cout << doc.patientList[i] << endl << endl;
}
cout << "Case passed...\n\n" << endl;
//Tests the number of patients printPatients() printed
//and compares to numPatients
cout << "\nTest for printPatients() function: \n\n";
assert(true == (doc.numPatients == doc.printPatients()));
cout << "Case passed...\n\n";
//Tests reset() to ensure numPatients is equal to zero
//and patient list is empty
cout << "Test for reset() function: \n\n";
doc.reset();
assert(true == (doc.numPatients == 0));
doc.printPatients();
cout << endl;
cout << "Case passed...\n\n" << endl;
//restore original values that were recently reset
doc.name = storeName;
doc.numPatients = storeNumPatients;
delete [] doc.patientList;
doc.patientList = new string[doc.numPatients];
for (int i = 0; i < doc.numPatients; i++)
{
doc.patientList[i] = storePatientList[i];
}
//Tests if operator++() function successfully created a
//copy of the Patient list
cout << "Test for operator++() function: \n\n";
doc.operator++();
assert(true == (checkEqualArrays(doc.patientList, copyList, doc)));
doc.patientList = new string[doc.numPatients];
for (int i = 0; i < doc.numPatients; i++)
{
doc.patientList[i] = storePatientList[i];
}
cout << "Printing copied patient list... \n\n";
for (int i = 0; i < doc.numPatients; i++)
{
cout << copyList[i] << endl << endl;
}
cout << "Case passed...\n\n";
//Tests to ensure that Doctor destructor deletes
//previous allocated memory
cout << "\nTest for ~Doctor() function: \n\n";
doc.~Doctor();
cout << "Doctor name: " << doc.name << endl << endl;
cout << "Number of Patients: " << doc.numPatients << endl << endl;
cout << "List of Patients: " << endl << endl;
for (int i = 0; i < doc.numPatients; i++)
{
cout << doc.patientList[i] << endl << endl;
}
delete [] storePatientList;
storePatientList = NULL;
delete [] copyList;
copyList = NULL;
cout << "Case passed...\n\n";
}
There are multiple memory management errors. The most obvious one is that the user-defined copy constructor for Doctor is missing, which results in multiple Doctors referring to the same array and, ultimately, double-free. The copy constructor is called each time you invoke runTests() or checkEqualArrays()
There is also a memory leak on line 261
There are still more memory errors after those, that are showing up on memory profiler.
It's a requirement for the assignment to use dynamic arrays. Again, I'm just learning how to program in C++. The reason I continuously allocate new memory is because the destructor was automatically being called and deallocating the array. I have no clue why that is happening.
How do I make a copy constructor? Do you mean overloading the default constructor?
Also, do you recommend I install a memory profiler?