简体   繁体   中英

Can not isolate memory leak

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM