1

I am submitting my school workshop through matrix and I am getting this warning about memory leak, however, when I compile it and run through the g++ command or VS, it does not show any warnings or errors.

That is the beginning of the submission

Checking due date:
ON TIME.

Compiling:
g++ -Wall -std=c++11 -o ws utils.o School.cpp schoolTester.cpp Subject.cpp utils.cpp 2> errors.txt

Compile result:
Success! no errors or warnings...

Testing execution:
READ THE FOLLOWING CAREFULLY!
I am about to execute the tester and capture the output in "student_output.txt"
Please enter the values carefuly and exactly as instructed.
Press <ENTER> to start...
Script started, file is student_output.txt
==203824== Memcheck, a memory error detector
==203824== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==203824== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==203824== Command: ws
==203824==
Begin Testing the Program!
--------------------------

Please enter the name of the school:
>

When I ran the code I get this summary

------------------------
End Testing the Program!
==209192==
==209192== HEAP SUMMARY:
==209192==     in use at exit: 200 bytes in 1 blocks
==209192==   total heap usage: 9 allocs, 8 frees, 366 bytes allocated
==209192==
==209192== LEAK SUMMARY:
==209192==    definitely lost: 200 bytes in 1 blocks
==209192==    indirectly lost: 0 bytes in 0 blocks
==209192==      possibly lost: 0 bytes in 0 blocks
==209192==    still reachable: 0 bytes in 0 blocks
==209192==         suppressed: 0 bytes in 0 blocks
==209192== Rerun with --leak-check=full to see details of leaked memory
==209192==
==209192== For counts of detected and suppressed errors, rerun with: -v
==209192== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Script done, file is student_output.txt

Here is the code itself:

School.cpp

namespace sdds {

    School Sch;
    Subject Sub[5];

    void read(School& Sch) {
        Sch.m_name = new char[30];
        char name [61];
        cout << "Please enter the name of the school:\n> ";
        read( name, 61, "Name is too long, only 60 characters allowed!\nRedo Entry: ");

        strcpy(Sch.m_name, name);
        cout << "Please enter the number of subjects offered by " << Sch.m_name << ": ";
        Sch.m_noOfSubjects = new int[50];
        read(*Sch.m_noOfSubjects, 2, 50, "Invalid Number of subjects, 2<=ENTRY<=50\nRedo Entry: ");
        Sch.m_subjects = new int[*Sch.m_noOfSubjects];

        for (int i = 0; i < *Sch.m_noOfSubjects; i++) {
            cout << i+1 << ") ------------------------------" << endl;
            read(Sub[i]);


        }
    }

    int report(const School&Sch) {
        int totalEnr = 0;

        cout << Sch.m_name<<endl;
        cout << "Subject Enrollments" << endl;

        for (int i = 0; i < *Sch.m_noOfSubjects; i++) {
            totalEnr += report(Sub[i]);



        }
        cout << "Total enrollment: " << totalEnr;
        return totalEnr;
    }

    void freeMem(School& Sch) {

        delete [] Sch.m_name;
        Sch.m_name = NULL;

        for (int i = 0; i < *Sch.m_noOfSubjects; i++) {
            freeMem (Sub[i]);
        }

        delete [] Sch.m_subjects;
        Sch.m_subjects = NULL;
    }

}

Subject.cpp

namespace sdds {






    void read(char* str) {

        cout << "Enter subject name: ";

        read(str, 71, "Name is too long, only 70 characters allowed!\nRedo Entry : ");

    }

    void read(int& noofSections) {

        cout << "Enter number of sections: ";

        read(noofSections, 0, 11, "Invalid Number of sections, 1<=ENTRY<=10\nRedo Entry: ");

    }

    void read(int noOfStdsInSecs[], int noOfSections) {
                cout << "Enter the number of students in each one of the " << noOfSections << " sections:" << endl;


        for (int i = 0; i < noOfSections; i++) {

            cout << i+1 << ": ";
            read(noOfStdsInSecs[i], 5, 35, "Invalid Number of students, 5<=ENTRY<=35\nRedo Entry: ");

        }


    }

    void read(Subject& Sub) {


        char subjectName[71];
        read(subjectName);
        Sub.m_subjectName = new char[50];
        strcpy(Sub.m_subjectName, subjectName);

        Sub.m_noOfSections = new int;
        read(*Sub.m_noOfSections);


        Sub.m_noOfStdsInSecs = new int [*Sub.m_noOfSections];
        read(Sub.m_noOfStdsInSecs, *Sub.m_noOfSections);

    }

void freeMem(Subject& Sub) {

        delete[] Sub.m_subjectName;
        Sub.m_subjectName = NULL;
        delete Sub.m_noOfSections;
        Sub.m_noOfSections = NULL;
        delete [] Sub.m_noOfStdsInSecs;
        Sub.m_noOfStdsInSecs = NULL;

    }

UPDATED: After turning a Sch.m_noOfSubjects into just an int I keep getting the same heap summary, but now it literally says that everything is fine but because of it I can not submit it, since my output and the output from the submission matrix script do not match. Is there a way to somehow turn it off?

------------------------
End Testing the Program!
==1821==
==1821== HEAP SUMMARY:
==1821==     in use at exit: 0 bytes in 0 blocks
==1821==   total heap usage: 8 allocs, 8 frees, 166 bytes allocated
==1821==
==1821== All heap blocks were freed -- no leaks are possible
==1821==
==1821== For counts of detected and suppressed errors, rerun with: -v
==1821== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Script done, file is student_output.txt

Checking output:
In line number 33 of your output:
The output should be:

^
But your output is:
[38;5;9m------------------------
^
  • 1
    The school is using valgrind. Very cool of them to do this. You may find it worthwhile to get a Linux virtual machine you can use to to do the same. The full valgrind output can usually tell you exactly what was lost and give you an idea of where to start looking. – user4581301 Sep 20 '19 at 00:49
  • You don't seem to be freeing `Sch.m_noOfSubjects`. Also I don't see anywhere the code for `freeMem(Subject& sub)` [rant] If this how they teach C++ no wonder people claim it to be complicated [/rant] – Mirko Sep 20 '19 at 00:57
  • @user4581301 Is downloading a VM of a Linux the only way to get the full understanding of the leak? – Nightingale Sep 20 '19 at 01:01
  • You can also count: 3 `new` in `read`, 2 `delete` in `freeMem`... – Mirko Sep 20 '19 at 01:04
  • @Mirko I didnt post it smh, I have added freeMem for the subject – Nightingale Sep 20 '19 at 01:04
  • @Mirko I am running a for loop with the function which I just included to the post. It deletes the allocated memory of multiple subjects structs – Nightingale Sep 20 '19 at 01:06
  • No. Valgrind is just a tool. It's a very effective tool , but you can also go through your code carefully and do the book-keeping yourself. Make sure that for every `new` you have a matching `delete`. Where things get tricky is you have to make damn sure that that delete is hit exactly once. Allow a path around the `delete` and the program leaks. Hit the `delete` twice and the program probably crashes. – user4581301 Sep 20 '19 at 01:07
  • Read the @user4581301 post below. As both told you, you're not `delete`ing the memory from the `Sch.m_noOfSubjects = new int[50];` in `freeMem(School& Sch)` – Mirko Sep 20 '19 at 01:11
  • 1
    Because memory management is such a time-consuming chore and the entry vector for a huge proportion of software bugs, the best software completely avoids having to do it. And when they do have to, they automate it . Here's a good discussion: [Why should C++ programmers minimize use of 'new'?](https://stackoverflow.com/questions/6500313/why-should-c-programmers-minimize-use-of-new) – user4581301 Sep 20 '19 at 01:14
  • Case in point, if you always `Sch.m_noOfSubjects = new int[50];`, this is a great sign that what you really want is to replace `int * m_noOfSubjects;` with `int m_noOfSubjects[50];`. But this could be a problem. What if 51 subjects are offered? What you often want to do is either A) determine the number of subjects and dynamically size the array accordingly or B) use a resizable data structure so you can keep adding more subjects and... Oh fudge. That's what my answer is missing. Why is `m_noOfSubjects` not just a plain old `int`? 'scuse me. Need to edit. – user4581301 Sep 20 '19 at 01:23

1 Answers1

2

The Leak is Just a Sideshow

There should be no leak at all. The correct things are being deallocated and the error is in one thing being allocated unnecessarily.

Look at how m_noOfSubjects is used after the array has been allocated:

read(*Sch.m_noOfSubjects, 2, 50, "Invalid Number of subjects, 2<=ENTRY<=50\nRedo Entry: ");

and

Sch.m_subjects = new int[*Sch.m_noOfSubjects];

and

for (int i = 0; i < *Sch.m_noOfSubjects; i++) 

All use exactly one value: the very first. This is not the behaviour of an array. This is the behaviour of a single int.

m_noOfSubjects should not be a pointer to an array or an int or anything like that. It should just be a dumb, ol' int.

In School's definition, replace

int * m_noOfSubjects;

with

int m_noOfSubjects;

then remove the allocation

Sch.m_noOfSubjects = new int[50];

and finally eliminate all of the dereferences. eg

read(*Sch.m_noOfSubjects, 2, 50, "Invalid Number of subjects, 2<=ENTRY<=50\nRedo Entry: ");
     ^ remove

and

Sch.m_subjects = new int[*Sch.m_noOfSubjects];
                         ^ remove

and

for (int i = 0; i < *Sch.m_noOfSubjects; i++) 
                    ^ remove

Thought process on tracking and avoiding memory leaks (original answer)

The report says one block of 200 bytes is lost. You can look though your code for where you allocate 200 bytes and investigate more closely. For example, if int is 32 bit, Sch.m_noOfSubjects = new int[50]; fits the bill 32 bits = 4 bytes. 4*50 = 200.

Let's follow m_noOfSubjects through and make sure it is correctly managed.

one CTRL+F later...

Sure enough I cannot find a delete of m_noOfSubjects anywhere in the given code.

How do we fix this? std::vector<int> should be the go to for handling a problem like this. vector looks after all of the resource management for you from allocating to deallocating and throws in correctly handling copying and assignment at the same time.

That said, I suspect what this assignment is supposed to teach you is RAII. In that case what you want to do is add a constructor and a destructor (and a copy constructor and an assignment operator as well because if you need a destructor, you almost always need special code to handle copying) to the School class. Don't allocate School's resources in some read free function that doesn't give a damn about the health and well being of the School class. School should look out for itself by allocating storage in its constructor or in its own input method. Later, the the destructor guarantees that all of School's resources are freed as soon as a School goes out of scope. All you have to so is make sure the School goes out of scope.

user4581301
  • 29,019
  • 5
  • 26
  • 45
  • Unfortunately, the assignment is not supposed to teach us RAII. We have a lab assignment pdf file which says which functions should we declare and when to use them. And there is nothing about conctructor and destructor (((( – Nightingale Sep 20 '19 at 01:31
  • Thank you so much for the such big and helpful answer. I changed my code just like you said, but unfortunately I am still getting that heap summary but now without any errors and leaks. (I updated the question and added the new summary) – Nightingale Sep 20 '19 at 01:56
  • That looks to be a new and different bug. It's best to keep one question to one problem so that the question remains useful to future askers. If you pack too much into a question they become too specific and less useful rather than more. My recommendation is to feed in some test inputs and make sure you don't have a case that's running off the end and spitting out garbage or otherwise printing erroneous results. If you can't find the problem, ask a new question. – user4581301 Sep 20 '19 at 02:08