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

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

Восстановить пароль Регистрация
 
kultttemo
3 / 3 / 1
Регистрация: 10.05.2014
Сообщений: 15
10.05.2014, 20:56     Деструктор класса. Как правильно очистить память? #1
Добрый день! Написал прогу бинарного дерева поиска, все работает, но нужен совет как убрать за собой, тобесь очистить память во избежания утечек. Сам пытался писать 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++ Как правильно освободить память
C++ деструктор не может очистить память
Динамическая память (строки), деструктор C++
Ругается на деструктор (выделял динамически память). Почему? C++
Деструктор класса C++
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
Melg
416 / 152 / 62
Регистрация: 23.09.2013
Сообщений: 306
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;
}
Убежденный
Системный программист
 Аватар для Убежденный
14208 / 6223 / 987
Регистрация: 02.05.2013
Сообщений: 10,368
Завершенные тесты: 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
416 / 152 / 62
Регистрация: 23.09.2013
Сообщений: 306
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) {
}
kultttemo
3 / 3 / 1
Регистрация: 10.05.2014
Сообщений: 15
11.05.2014, 01:16  [ТС]     Деструктор класса. Как правильно очистить память? #6
Цитата Сообщение от Melg Посмотреть сообщение
Пришлось волгриндиком пройтись. У Вас использовались указатели на left и right - не инициализированными
За это спасибо, и правда работает. Походу пытался удалить указатель в стеке или указатель, вмещающий мусор.
Yandex
Объявления
11.05.2014, 01:16     Деструктор класса. Как правильно очистить память?
Ответ Создать тему
Опции темы

Текущее время: 23:54. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru