无法隔离内存泄漏

Can not isolate memory leak

我正在使用 Visual Studio 泄漏检测工具:https://visualstudiogallery.msdn.microsoft.com/7c40a5d8-dd35-4019-a2af-cb1403f5939c

这给了我泄漏的行号,因为我一辈子都无法得到 #define _CRTDBG_MAP_ALLOC 来为我提供描述性输出。如果您发现我在我的代码中使用不正确,请说出来,我想知道如何正确使用它,但就目前而言,可视化泄漏检测工具运行良好。

我不断发现 2 个内存泄漏,一个在 project4.cpp 第 58 行,另一个在 tasklist.cpp 第 13 行。

第一个泄漏,project4.cpp 第 58 行,当我调用 delete myTaskList.[=17 时,应该由我主函数的 return 语句之前的 delete 语句密封=]

第二次泄漏,taskList.cpp 第 13 行,当我的 TaskList class 的重写析构函数如此调用时应该被密封:

//destructor to delete all dynamically allocated memory
TaskList::~TaskList() {
    delete[] arrayOfTasks;
    arrayOfTasks = NULL;
}

我很困惑为什么这些泄漏仍然出现。这是我的主要功能:

#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;
}

这里是 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 != '[=12=]'){ //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;
}

这是我收到的错误的副本:

在 writeTasks 中,如果无法打开文件,则打印错误(我可以在上面的命令提示符中看到),然后退出!所以当然一​​切都会泄漏。

在我看来,最好的办法是避免在发生错误时调用 exit:使用更强大的错误处理方案(如异常)。