2012-05-13 2 views
2

Функция addStudent и функция mainMenu являются важными.Это ли утечка памяти?

#include <iostream> 
#include <string> 

using namespace std; 

struct Student 
{ 
    string name; 
    string major; 
    Student *p_next; 
}; 

Student *addStudent(Student *p_students) 
{ 
    Student *p_new_student = new Student; 
    cout << "Student name: \n"; 
    cin >> p_new_student->name; 
    cout << p_new_student->name << "'s major: \n"; 
    cin >> p_new_student->major; 

    Student *p_place_holder = new Student; 
    Student *p_all_students = new Student; 
    p_all_students = p_students; 
    p_place_holder = NULL; 

    if (p_students == NULL) // Adds the first element to the linked list which was initialized to NULL 
    { 
     p_new_student->p_next = p_students; 
     delete p_place_holder; 
     delete p_all_students; 
     return p_new_student; 
    } 

    else // Adds elements beyond the first element to the linked list 
    { 
     while (p_all_students != NULL) 
     { 
     if (p_new_student->name.compare(p_all_students->name) <= 0) 
     { 
      if (p_place_holder == NULL) /* if p_new_student->name is before 
      p_all_students->name and p_all_students is still the first element in the list*/ 
      { 
       p_new_student->p_next = p_all_students; 
       p_all_students = p_new_student; 
       delete p_place_holder; 
       return p_all_students; 
      } 

      else 
      { 
       p_new_student->p_next = p_all_students; 
       p_place_holder->p_next = p_new_student; 
       return p_students; 
      } 

     } 

     else if (p_new_student->name.compare(p_all_students->name) > 0) 
     { 
      p_place_holder = p_all_students; 
      p_all_students = p_all_students->p_next; 
     } 
     } 
    } 
} 

void mainMenu(Student *p_students) 
{ 
    int response = 0; 
    cout << "1. Add Student\n"; 
    cout << "2. View Students\n"; 
    cin >> response; 

    if (response == 1) // calls addStudent 4 times and then mainMenu 
    { 
     p_students = addStudent(p_students); 
     p_students = addStudent(p_students); 
     p_students = addStudent(p_students); 
     p_students = addStudent(p_students); 
     mainMenu(p_students); 
    } 

    else if (response == 2) // lists the students and their majors and then exits 
    { 
     while (p_students != NULL) 
     { 
     cout << p_students->name << '\n'; 
     cout << p_students->major << "\n\n"; 
     p_students = p_students->p_next; 
     } 
    } 

    delete p_students; // hopefully deletes all allocated memory 
} 

int main() 
{ 
    Student *p_students = new Student; 
    p_students = NULL; 

    mainMenu(p_students); 
} 

В основном интересно, удаляет ли p_students; в функции mainMenu будет правильно удалять всю выделенную память, чтобы программа не просачивала память. Любая помощь приветствуется, спасибо много.

+3

Это много кода, вы должны попытаться уменьшить его до минимального скомпилированного кода, который все равно будет описывать проблему. – amit

+1

Кроме того, если вы запускаете свою программу с помощью утилиты, такой как _valgrind_, вы увидите, что она теряет память, не спрашивая здесь! –

+0

@MrLister: Гораздо лучше иметь возможность читать и объяснять код для предотвращения утечек. –

ответ

6

Эти линии будут просачиваться экземпляр Student:

Student *p_place_holder = new Student; 
Student *p_all_students = new Student; 
p_all_students = p_students; 
p_place_holder = NULL; 

Вы выделяете студент, назначить его p_place_holder, а потом перезаписать указатель с NULL без удаления экземпляра.

Вы также:

p_students = addStudent(p_students); 
p_students = addStudent(p_students); 
p_students = addStudent(p_students); 
p_students = addStudent(p_students); 

, который перепишет p_students три раза, не пытаясь освободить память в старом значении.

Большая проблема заключается в том, что вы заканчиваете delete p_students, но это не будет проверять структуру Student, чтобы найти указатель внутри нее, удалить ее и т. Д., Рекурсивно, как вы надеетесь. Вы пропускаете почти всю память, которую вы выделили.

Я думаю, что вы не понимаете, как новые и удалить пару вместе.

+0

Я, это моя первая программа, использующая два. Если я использую delete в функции addStudent, он удалит ученика p_students, который я использую, чтобы правильно указать на первый элемент в списке? Должен ли я назначать p_students новому ученику, а затем удалять старый при каждом вызове функции? –

+0

Ой также, будет ли цикл while работать в конце mainMenu, чтобы удалить все экземпляры Student в связанном списке? Например, while (p_students! = NULL) {// code}? –

+0

@BlakeMadden: каждый раз, когда вы отказываетесь от заостренного значения, вам нужно его удалить. Это может быть, когда вы перезаписываете указатель или когда вы удаляете структуру, в которой есть указатель. –

0

Чтобы избежать утечек памяти, вы должны использовать указатели принудительного владения, например unique_ptr и shared_ptr. Вы никогда не сможете эффективно предотвратить утечки с помощью delete.

+2

"никогда"? Удивительно, что любое программное обеспечение было написано вообще до того, как эти классы были доступны ... :) –

+1

Я использую 'new' /' delete' исключительно и никогда не испытываю никаких проблем. Я думаю, что это удобно, чтобы иметь некоторый опыт. И для случаев, когда проблемы возникают, Valgrind - очень эффективная помощь. – TaZ

+0

@NedBatchelder: Люди просто жили с ошибками. Кроме того, программное обеспечение было намного, намного меньше и намного менее сложным. – Puppy

Смежные вопросы