Форум программистов, компьютерный форум CyberForum.ru

С++ для начинающих

Войти
Регистрация
Восстановить пароль
 
kultttemo
3 / 3 / 1
Регистрация: 10.05.2014
Сообщений: 15
#1

Деструктор класса. Как правильно очистить память? - C++

10.05.2014, 20:56. Просмотров 1102. Ответов 5
Метки нет (Все метки)

Добрый день! Написал прогу бинарного дерева поиска, все работает, но нужен совет как убрать за собой, тобесь очистить память во избежания утечек. Сам пытался писать delete в деструторе, но толку не дало. Вот коды:
//Tree.h
C++ (Qt)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#ifndef TREE_H
#define TREE_H
 
 
class Tree
{
    public:
        Tree();
        Tree(int data);
        virtual ~Tree();
        void add(int data);
        int getData();
        int maximumElement();
        int minimumElement();
        void printMaximumElements();
        void printMinimumElements();
    protected:
    private:
        int data;
        Tree *right;
        Tree *left;
};
 
#endif // TREE_H
//Tree.cpp
C++ (Qt)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
#include "Tree.h"
#include <iostream>
 
using namespace std;
 
Tree::Tree() : data(0)
{
 
}
 
Tree::Tree(int data)
{
    this->data = data;
}
 
Tree::~Tree()
{
 
}
 
void Tree::add(int data)
{
    if (this->data > data)
    {
        if (!this->left)
        {
            cout << "n< ";
            this->left = new Tree;
            this->left->data = data;
            return;
        }
        cout << "<";
        this->left->add(data);
        return;
    }else
    {
        if (!this->right)
        {
            cout << "n> ";
            this->right = new Tree;
            this->right->data = data;
            return;
        }
        cout << ">";
        this->right->add(data);
        return;
    }
 
    cout << "Error! Something went wrong in Tree" << endl;
}
 
int Tree::getData()
{
    return this->data;
}
 
int Tree::maximumElement()
{
    return (this->right)?this->right->maximumElement():this->data;
}
 
int Tree::minimumElement()
{
    return (this->left)?this->left->minimumElement():this->data;
}
 
void Tree::printMaximumElements()
{
    cout << this->data << " -> ";
    if (this->right)
        this->right->printMaximumElements();
}
 
void Tree::printMinimumElements()
{
    cout << this->data << " -> ";
    if (this->left)
        this->left->printMinimumElements();
}
//main.cpp
C++ (Qt)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <iostream>
#include "Tree.h"
 
using namespace std;
 
int main()
{
    Tree *root = new Tree(10);
 
    root->add(12);
    root->add(15);
    root->add(14);
    root->add(3);
    root->add(1);
    root->add(2);
    root->add(-1);
    cout << endl;
    cout << root->getData() << endl;
    cout << root->maximumElement() << endl;
    cout << root->minimumElement() << endl;
    cout << "\nMaximum elements: ";
    root->printMaximumElements();
    cout << "\n\nMinimum elements: ";
    root->printMinimumElements();
    cout << endl;
    delete root;
    return 0;
}

Вопрос в правильном деструкторе. Я ничего в нем не менял, но судя по логике указатели на правое и левое поддерево не удаляются. При попытке задать что-то типа:
C++ (Qt)
1
2
3
4
5
if (this->right)
{this->right->~Tree(); }
if (this->left)
{this->left->~Tree();}
this->delete;
Прошу обратить внимание на то, что деструктор виртуальный, ибо если я убираю virtual, то у меня прога зацикливается.
Лучшие ответы (1)
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
10.05.2014, 20:56     Деструктор класса. Как правильно очистить память?
Посмотрите здесь:

деструктор не может очистить память - C++
Всем привет. Ребят, проблема такая. Есть класс который предназначен для хранения двумерной матрицы. Вот: class intArr{ int** arr;...

Как определить, сработал ли деструктор класса - C++
Пишу класс, пишу деструктор, но как определить, что деструктор сработал? Сам код: class array{ private: int *arr; public: ...

Подскажите как правильно добавить виртуальный деструктор - C++
Доброго времени суток Подскажите пожалуйста, как правильно добавить виртуальный деструктор в класс Int, Double, String и что он должен...

Как правильно сохранить структуру, унаследованную от структуры, содержащую виртуальный деструктор? - C++
Здравствуйте! Имеется структура: struct Product { int mId; double mCost; int mAmount; Product() {}

Как правильно очистить двухмерный вектор string-ов? - C++
Всем привет! Есть двухмерный вектор string: std::vector&lt;std::vector&lt;std::string&gt;&gt; functions(2); В ходе работы программы вектор должен...

Деструктор и динамическая память - C++
Вечер добрый, форумчане. Создал класс с матрицами, динамически выделил память. Конструктор копии вроде правильный, деструктор тоже, но...

После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
Melg
538 / 159 / 64
Регистрация: 23.09.2013
Сообщений: 314
10.05.2014, 22:14     Деструктор класса. Как правильно очистить память? #2
Насколько я понял из Вашего кода, новые объекты в куче выделяются при помощи операции new всего в трех местах.
Первое место:
C++
1
  Tree *root = new Tree(10);
Второе место:
C++
1
  this->left = new Tree;
Третье место:
C++
1
          this->right = new Tree;
Вся соль управления памятью заключается в том, что число памяти выделенное при помощи оператора new должно совпадать с числом памяти удаленного delete. В Вашем случае это означает, что для каждого из 3-х new должен существовать delete. (Подразумевая, что все адреса объектов, полученные вследствие вызова операторов new сохраняют данные в указатели, и ни один из них не перезатирается каким-либо другим значением).

Тогда деструктор должен выглядеть следующим образом :

C++
1
2
3
4
5
6
7
8
Tree::~Tree() {
  if (right) {
      delete right;
    }
  if (left) {
      delete left;
    }
}
или как Вам привычнее- судя по вашему коду:
C++
1
2
3
4
5
6
7
8
Tree::~Tree() {
  if (this->right) {
      delete this->right;
    }
  if (this->left) {
      delete this->left;
    }
}
Первая Ваша ошибка - попытка вызывать деструктор явным образом :
C++
1
{this->right->~Tree(); }
Это не является правильным. Поскольку ключевое слово delete внутри себя содержит не только операции по освобождению памяти, переданной ей в качестве операнда, но и вызов деструктора.
Кроме того, интересно узнать - что Вы подразумевали под зацикливанием программы при невиртуальном деструкторе?

Для верификации на предмет утечек можете использовать мою версию (единым cpp файлом):

Кликните здесь для просмотра всего текста
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
#include <iostream>
 
using namespace std;
 
class Tree {
public:
  Tree();
  Tree(int data);
  ~Tree();
  void add(int data);
  int getData();
  int maximumElement();
  int minimumElement();
  void printMaximumElements();
  void printMinimumElements();
protected:
private:
  int data;
  Tree *right;
  Tree *left;
};
 
Tree::Tree() : data(0) {
}
 
Tree::Tree(int data) {
  this->data = data;
}
 
Tree::~Tree() {
  if (this->right) {
      delete this->right;
    }
  if (this->left) {
      delete this->left;
    }
}
 
void Tree::add(int data) {
  if (this->data > data) {
      if (!this->left) {
          cout << "n< ";
          this->left = new Tree;
          this->left->data = data;
          return;
        }
      cout << "<";
      this->left->add(data);
      return;
    } else {
      if (!this->right) {
          cout << "n> ";
          this->right = new Tree;
          this->right->data = data;
          return;
        }
      cout << ">";
      this->right->add(data);
      return;
    }
  cout << "Error! Something went wrong in Tree" << endl;
}
 
int Tree::getData() {
  return this->data;
}
 
int Tree::maximumElement() {
  return (this->right)?this->right->maximumElement():this->data;
}
 
int Tree::minimumElement() {
  return (this->left)?this->left->minimumElement():this->data;
}
 
void Tree::printMaximumElements() {
  cout << this->data << " -> ";
  if (this->right) {
      this->right->printMaximumElements();
    }
}
 
void Tree::printMinimumElements() {
  cout << this->data << " -> ";
  if (this->left) {
      this->left->printMinimumElements();
    }
}
 
int main(int argc, char *argv[]) {
  Tree *root = new Tree(10);
  root->add(12);
  root->add(15);
  root->add(14);
  root->add(3);
  root->add(1);
  root->add(2);
  root->add(-1);
  cout << endl;
  cout << root->getData() << endl;
  cout << root->maximumElement() << endl;
  cout << root->minimumElement() << endl;
  cout << "\nMaximum elements: ";
  root->printMaximumElements();
  cout << "\n\nMinimum elements: ";
  root->printMinimumElements();
  cout << endl;
  delete root;
  return 0;
}
Убежденный
Системный программист
Эксперт С++
15298 / 6930 / 1096
Регистрация: 02.05.2013
Сообщений: 11,340
Завершенные тесты: 1
10.05.2014, 22:21     Деструктор класса. Как правильно очистить память? #3
Цитата Сообщение от kultttemo Посмотреть сообщение
Написал прогу бинарного дерева поиска, все работает, но нужен совет как убрать за собой, тобесь очистить память во избежания утечек.
Для начала разберитесь (в смысле - напишите или объявите закрытыми)
конструктор копирования и оператор присваивания. Без них ваш класс
перестанет работать после создания первой же своей копии.

Цитата Сообщение от Melg Посмотреть сообщение
Тогда деструктор должен выглядеть следующим образом :
C++
1
2
3
4
5
6
7
8
Tree::~Tree() {
 if (right) {
 delete right;
 }
 if (left) {
 delete left;
 }
}
По стандарту языка C++, delete на null-указателе разрешена и
не выполняет никаких действий (no-op). Поэтому можно
упростить так:

C++
1
2
3
4
5
Tree::~Tree()
{
    delete right;
    delete left;
}
kultttemo
3 / 3 / 1
Регистрация: 10.05.2014
Сообщений: 15
10.05.2014, 23:22  [ТС]     Деструктор класса. Как правильно очистить память? #4
Цитата Сообщение от Melg Посмотреть сообщение
Tree::~Tree() {
* if (right) {
* * * delete right;
* * }
* if (left) {
* * * delete left;
* * }
}
Вот так пишу и программа аварийно завершается.

Цитата Сообщение от Melg Посмотреть сообщение
Для верификации на предмет утечек можете использовать мою версию (единым cpp файлом):
У меня ваша версия зацикливается. Выводит символ ">" пока не крашнется.
Melg
538 / 159 / 64
Регистрация: 23.09.2013
Сообщений: 314
11.05.2014, 00:00     Деструктор класса. Как правильно очистить память? #5
Сообщение было отмечено автором темы, экспертом или модератором как ответ
Вот версия, которая должна работать :

Кликните здесь для просмотра всего текста
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
#include <iostream>
 
using namespace std;
 
class Tree {
public:
  Tree();
  Tree(int data);
  ~Tree();
  void add(int data);
  int getData();
  int maximumElement();
  int minimumElement();
  void printMaximumElements();
  void printMinimumElements();
protected:
private:
  int data;
  Tree *right;
  Tree *left;
};
 
Tree::Tree() : data(0),
  right(NULL),
  left(NULL) {
}
 
Tree::Tree(int data) : data(data),
  right(NULL),
  left(NULL) {
}
 
Tree::~Tree() {
  if (this->right) {
      delete this->right;
    }
  if (this->left) {
      delete this->left;
    }
}
 
void Tree::add(int data) {
  if (this->data > data) {
      if (!this->left) {
          cout << "n< ";
          this->left = new Tree;
          this->left->data = data;
          return;
        }
      cout << "<";
      this->left->add(data);
      return;
    } else {
      if (!this->right) {
          cout << "n> ";
          this->right = new Tree;
          this->right->data = data;
          return;
        }
      cout << ">";
      this->right->add(data);
      return;
    }
  cout << "Error! Something went wrong in Tree" << endl;
}
 
int Tree::getData() {
  return this->data;
}
 
int Tree::maximumElement() {
  return (this->right)?this->right->maximumElement():this->data;
}
 
int Tree::minimumElement() {
  return (this->left)?this->left->minimumElement():this->data;
}
 
void Tree::printMaximumElements() {
  cout << this->data << " -> ";
  if (this->right) {
      this->right->printMaximumElements();
    }
}
 
void Tree::printMinimumElements() {
  cout << this->data << " -> ";
  if (this->left) {
      this->left->printMinimumElements();
    }
}
 
int main(int argc, char *argv[]) {
  Tree *root = new Tree(10);
  root->add(12);
  root->add(15);
  root->add(14);
  root->add(3);
  root->add(1);
  root->add(2);
  root->add(-1);
  cout << endl;
  cout << root->getData() << endl;
  cout << root->maximumElement() << endl;
  cout << root->minimumElement() << endl;
  cout << "\nMaximum elements: ";
  root->printMaximumElements();
  cout << "\n\nMinimum elements: ";
  root->printMinimumElements();
  cout << endl;
  delete root;
  return 0;
}


По крайней мере тут компилируется:
http://codepad.org/d6uaNtuU

Пришлось волгриндиком пройтись. У Вас использовались указатели на left и right - не инициализированными:

C++
1
2
3
4
5
6
7
8
9
Tree::Tree() : data(0)
{
 
}
 
Tree::Tree(int data)
{
    this->data = data;
}
Я добавил инициализацию нулевыми значениями в обеих перегрузках конструктора:

C++
1
2
3
4
5
6
7
8
9
Tree::Tree() : data(0),
  right(NULL),
  left(NULL) {
}
 
Tree::Tree(int data) : data(data),
  right(NULL),
  left(NULL) {
}
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
11.05.2014, 01:16     Деструктор класса. Как правильно очистить память?
Еще ссылки по теме:

Динамическая память (строки), деструктор - C++
Привет. Бьюсь уже час, помогите разобраться. Написал программу, в одной функции память выделил, в другой освобождаю. После выполнения...

Ругается на деструктор (выделял динамически память). Почему? - C++
Вот код: #include &lt;stdio.h&gt; #include &lt;conio.h&gt; #include &lt;time.h&gt; #include &lt;stdlib.h&gt; class MClass { private: int...

Как правильно освободить память - C++
Есть функция char* md5(const char*). Как освободить память выделенную ею? #include &lt;openssl\md5.h&gt; char* md5(const char* text) { ...

Как правильно освободить память - C++
Написал вот такой костыль: wchar_t* getDate() { time_t seconds = time(NULL); tm timeinfo = *(localtime(&amp;seconds)); return...

Как правильно освободить память - C++
Здравствуйте все! Подскажите, как правильно освобождать память, выделенную под массив оператором new? int *Arr = new int; ... delete...

Как правильно освободить память - C++
Здрасте! (Тема: Шаблоны функций.) Не могу правильно написать метод для освобождения памяти. В мейне делаю все необходимые мне...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
kultttemo
3 / 3 / 1
Регистрация: 10.05.2014
Сообщений: 15
11.05.2014, 01:16  [ТС]     Деструктор класса. Как правильно очистить память? #6
Цитата Сообщение от Melg Посмотреть сообщение
Пришлось волгриндиком пройтись. У Вас использовались указатели на left и right - не инициализированными
За это спасибо, и правда работает. Походу пытался удалить указатель в стеке или указатель, вмещающий мусор.
Yandex
Объявления
11.05.2014, 01:16     Деструктор класса. Как правильно очистить память?
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru