I am using the Visual Studio leak detection tool: https://visualstudiogallery.msdn.microsoft.com/7c40a5d8-dd35-4019-a2af-cb1403f5939c
Which gives me line numbers of my leaks, since I could not, for the life of me, get #define _CRTDBG_MAP_ALLOC
to provide me with descriptive output. If you see that I m using it incorrectly in my code please speak up, I would like to know how to use it correctly, but as it stands, the Visual Leak Detection Tool is working great.
I keep finding 2 memory leaks, one at project4.cpp line 58, and the other at tasklist.cpp line 13.
The first leak, project4.cpp line 58, should be sealed by the delete statement right before the return statement of my main function, when I call delete myTaskList
.
The second leak, taskList.cpp line 13, should be sealed when the overridden destructor for my TaskList class is called as so:
//destructor to delete all dynamically allocated memory
TaskList::~TaskList() {
delete[] arrayOfTasks;
arrayOfTasks = NULL;
}
I am stumped as to why these leaks still appear. Here is my main function:
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
#include <iostream>
#include <fstream>
#include <cstring>
#include <cstdlib>
#include "Task.h"
#include "TaskList.h"
#include <vld.h>
using namespace std;
using std::cout;
using std::cin;
//global const declarations
const int NAME_COL_WIDTH = 30;
const int EMAIL_COL_WIDTH = 40;
const int MAX_TaskS = 100;
//function to read in user input as c-string
void readString (const char prompt[], char inputStr[], int maxChar)
{
cin.get();//swallow the newline character if present
cin.clear();
//read until reaches the maxChar limit or encounters '\n'
cout << prompt << endl;
cin.get(inputStr, maxChar, '\n');
while(!cin)
{
cin.clear ();
cin.ignore (100, '\n');
cout << prompt << endl;
cin.get(inputStr, maxChar, '\n');
}
cout << endl;
}
int main() {
//memory leak detection
_CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
const char * taskFile = "tasks.txt";
char isInputCorrect;
char menuSelection = 'x';
//instantiate new TaskList object
TaskList * myTaskList = new TaskList();
//now we load our saved tasks into our new TaskList object
(*myTaskList).loadTasks(taskFile);
//tell the user how many tasks were read from memory
cout << "After loading your file, you have " << (*myTaskList).getTotalTasks() <<
" saved Tasks\n" << endl;
while (true) { //menu loop
cout << "Please choose from the following selections:" << endl;
cout << "1. Enter a task or assignment" << endl;
cout << "2. Display all of the tasks that are in the file" << endl;
cout << "3. Find a task by course" << endl;
cout << "4. Quit\n" << endl;
cin >> menuSelection;
if (menuSelection == '1') {
char innerMenuSelection;
char task[MAX_CHAR];
int TaskSelection;
do{
char courseName[MAX_CHAR];
char taskDescription[MAX_CHAR];
char dueDate[MAX_CHAR];
readString("Please enter the course name: ",
courseName,MAX_CHAR);
readString("Please enter the task for this course: ",
taskDescription,MAX_CHAR);
readString("Please enter the due date for this task,\nIn MM/DD/YYYY format: ",
dueDate,MAX_CHAR);
//copy our attribute into our Task Object
//add our task to our object
(*myTaskList).addTask(courseName, dueDate, taskDescription);
cout << "You have entered " << courseName << " and " <<
taskDescription << endl;
cout << "Enter Y if this input is correct, or anything else to re-enter:"
<< endl << endl;
cin >> isInputCorrect;
} while (isInputCorrect != 'Y');
} else if (menuSelection == '2') {
(*myTaskList).printAllTasks();
} else if (menuSelection == '3') {
char searchString[MAX_CHAR];
int resultCount = 0;
int indexOfFirstMatchingTask = 0;
readString("Please enter the course name: ",
searchString,MAX_CHAR);
(*myTaskList).search(searchString, resultCount,
indexOfFirstMatchingTask);
} else if (menuSelection == '4') {
//we write our tasks to file to save for later use
(*myTaskList).writeTasks("tasks.txt");
break;
}
}
//deletion of dynamically allocated mem
delete myTaskList;
return 0;
}
And here is a copy of TaskList.cpp:
#include "Task.h"
#include "TaskList.h"
#include <iostream>
#include <cstring>
#include <fstream>
using namespace std;
//custom default constructor
TaskList::TaskList() {
totalTasks = 0;
arrayOfTasks = new Task [MAX_CHAR];
}
bool TaskList::search(char * searchString,
int &resultCount, int &indexOfFirstMatchingTask) {
resultCount = 0;//we reset resultCount if not passed with 0 value
bool isFound = false;
for (int i = 0; i < totalTasks+1; i++) {
if (strcmp(arrayOfTasks[i].getCourseName(), searchString) == 0) {
resultCount++;
cout << "You searched for: " << searchString << endl;
cout << "So far, " << resultCount <<
" match(es) have been found" << endl;
cout << "The task for this matching course is: " <<
endl << arrayOfTasks[i].getTaskDescription() << endl;
isFound = true;
}
}
if(isFound == false) {
cout << "No match found for: " << searchString << endl;
}
cout << endl;
return isFound;
}
//function to write our tasks to file when closing the program
void TaskList::writeTasks(const char* fileName)
{
ofstream out;
out.open (fileName);
if(!out)
{
out.clear();
cerr << endl << "Fail to open " << fileName << " for input!" <<
endl << endl;
exit(1);
}
for (int i = 0; i < totalTasks; i++) {
if(i != totalTasks-1) {
out << arrayOfTasks[i].getCourseName() <<
';' << arrayOfTasks[i].getTaskDescription() <<
';' << arrayOfTasks[i].getDueDate() << endl;
} else {
out << arrayOfTasks[i].getCourseName() <<
';' << arrayOfTasks[i].getTaskDescription() <<
';' << arrayOfTasks[i].getDueDate();
}
}
//close file
out.close();
}
//function to load our saved tasks from file
void TaskList::loadTasks(const char* fileName)
{
ifstream in;
char name[MAX_CHAR];
char tasks[MAX_CHAR];
char dueDate[MAX_CHAR];
in.open (fileName);
if(!in)
{
in.clear();
cerr << endl << "Fail to open " << fileName << " for input!" <<
endl << endl;
exit(1);
}
while (!in.eof())
{
in.get(name, MAX_CHAR, ';'); //read in Task name
in.get(); //remove field seperator ';'
in.get(tasks, MAX_CHAR, ';'); //read in task
in.get(); //remove field seperator ';'
in.get(dueDate, MAX_CHAR, '\n'); //read in Task dueDate
in.ignore(100, '\n'); //remove record seperator '\n'
//incriment the total number of rows we have read and create new Task
addTask(name, dueDate, tasks);
}
in.close();
}
//function to print all attributes of each task consecutively
void TaskList::printAllTasks() {
for(int i = 0; i < totalTasks; i++) {
//first we print the Task name
cout << "Course name: " << endl;
cout << arrayOfTasks[i].getCourseName();
cout << endl;
//now print the tasks for that Task
cout << "Task description:" << endl;
cout << arrayOfTasks[i].getTaskDescription();
cout << endl;
//now print due date
cout << "Task due date:" << endl;
cout << arrayOfTasks[i].getDueDate();
cout << endl;
}
cout << endl;
}
//function to add a task
void TaskList::addTask(const char * courseName, const char * dueDate,
const char * taskDescription) {
/*arrayOfTasks[totalTasks] = *new Task(courseName, dueDate,
taskDescription);*/
totalTasks++;
}
//function to return the current number of tasks
int TaskList::getTotalTasks() {
return totalTasks;
}
//function to print c-string
void TaskList::cStringPrint(char * arrayToPrint){
if(*arrayToPrint != '\0'){ //can alternatively swap '\x0' for NULL
cout << *arrayToPrint;
arrayToPrint++;
//recursive tail call on next element address
cStringPrint(arrayToPrint);
}
}
//destructor to delete all dynamically allocated memory
TaskList::~TaskList() {
delete[] arrayOfTasks;
arrayOfTasks = NULL;
}
Here is a copy of the error I receive:
In writeTasks, if the file can't be opened you print an error (which I can see in the command prompt above), then exit! So of course everything leaks.
Way I see it, your best bet is to just avoid calling exit when something bad happens: use a more robust error handling scheme (like exceptions).
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.