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

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

Войти
Регистрация
Восстановить пароль
 
 
Svinina
5 / 5 / 0
Регистрация: 28.11.2010
Сообщений: 81
#1

Чтобы не было утечек памяти - C++

10.11.2011, 22:15. Просмотров 815. Ответов 15
Метки нет (Все метки)

Товарищи, такой вопрос:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class node
{
int *a;
double *b;
vector<node *> vec;
public:
//тут методы
}
 
node::~node()
{
delete a;
delete b;
}
Все ли необходимое я очистил в деструкторе? С вектором что-нибудь надо делать?
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
10.11.2011, 22:15     Чтобы не было утечек памяти
Посмотрите здесь:
Подключении механизма обнаружение утечек памяти C++
Подскажите программу для диагностики утечек памяти C++
C++ Visual Studio 2015 Обнаружение утечек памяти
как проверить наличие утечек памяти в шаблоне? C++
C++ Написал свой string. Проверьте код на наличие подводных камней, утечек памяти и других ошибок
Вывести файл на экран, чтобы в каждой строке было не больше 40 символов, и количество строк было минимальным C++
C++ Создание объекта класса, чтобы он постоянно висел в памяти, и чтобы память выделялась один раз
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
Ma3a
Эксперт C++
616 / 460 / 31
Регистрация: 28.01.2011
Сообщений: 605
10.11.2011, 22:19     Чтобы не было утечек памяти #2
Svinina, каждый элемент в векторе тоже должен быть освобождён вручную, delete для них при разрушении вектора не вызывается.
Jupiter
Каратель
Эксперт С++
6553 / 3973 / 226
Регистрация: 26.03.2010
Сообщений: 9,273
Записей в блоге: 1
Завершенные тесты: 2
10.11.2011, 22:19     Чтобы не было утечек памяти #3
Цитата Сообщение от Svinina Посмотреть сообщение
Все ли необходимое я очистил в деструкторе? С вектором что-нибудь надо делать?
мало данных
DKOI
24 / 24 / 1
Регистрация: 08.09.2010
Сообщений: 136
10.11.2011, 22:21     Чтобы не было утечек памяти #4
Да, надо. Пробегитесь по вектору и поделяйте все элементы (если сами они не нужны после удаления объекта) а потом:
C++
1
vec.clear();
prazuber
109 / 109 / 3
Регистрация: 29.04.2010
Сообщений: 240
10.11.2011, 22:24     Чтобы не было утечек памяти #5
Я бы еще проверял указатель на null, прежде чем удалять.
Jupiter
Каратель
Эксперт С++
6553 / 3973 / 226
Регистрация: 26.03.2010
Сообщений: 9,273
Записей в блоге: 1
Завершенные тесты: 2
10.11.2011, 22:25     Чтобы не было утечек памяти #6
Цитата Сообщение от PraZuBeR Посмотреть сообщение
Я бы еще проверял указатель на null, прежде чем удалять.
зачем? delete можно применять к указателю на null
Svinina
5 / 5 / 0
Регистрация: 28.11.2010
Сообщений: 81
10.11.2011, 22:34  [ТС]     Чтобы не было утечек памяти #7
Ну если мало, то так:

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
class node
{
    int *a;
    double *b;
    vector<node *> vec;
public:
    node();
    node(node *n, node *m);
    ~node();
}
 
node::node()
{
    a = new int(1);
    b = new double(2.0);
}
node::node(node *n, node *m)
{
    a = new int(1);
    b = new double(2.0);
    vec.push_back(n);
    vec.push_back(m);
}
 
node::~node()
{
    delete a;
    delete b;
}
Добавлено через 3 минуты
Цитата Сообщение от DKOI Посмотреть сообщение
Да, надо. Пробегитесь по вектору и поделяйте все элементы (если сами они не нужны после удаления объекта) а потом:
C++
1
vec.clear();
В этом случае вызывается деструктор вектора?
И что вы имеете ввиду под "поделяйте все элементы"? Ерейзом из вектора их повыкидывать, или поубивать объекты, на которые ссылаются элементы этого вектора?
Bers
Заблокирован
10.11.2011, 22:37     Чтобы не было утечек памяти #8
имхо, в векторе над держать либо сами объекты, и тогда простого vec.clear() будит достаточно

либо держать интеллектуальные указатели на эти объекты, и тогда простого vec.clear() будит достаточно.

/ps вектор интеллектуальных указателей поганит память так же, как лист объектов.
Но работает медленнее, чем лист.
DKOI
24 / 24 / 1
Регистрация: 08.09.2010
Сообщений: 136
10.11.2011, 22:57     Чтобы не было утечек памяти #9
Цитата Сообщение от Svinina Посмотреть сообщение
И что вы имеете ввиду под "поделяйте все элементы"? Ерейзом из вектора их повыкидывать, или поубивать объекты, на которые ссылаются элементы этого вектора?
Поделять - сделать delete для каждой ссылки хранящейся в векторе. Иначе бы я сказал выкинуть Да и вообще, если еразить все елементы, зачем clear бы тогда вызвать?
Svinina
5 / 5 / 0
Регистрация: 28.11.2010
Сообщений: 81
10.11.2011, 23:07  [ТС]     Чтобы не было утечек памяти #10
Цитата Сообщение от DKOI Посмотреть сообщение
Поделять - сделать delete для каждой ссылки хранящейся в векторе. Иначе бы я сказал выкинуть Да и вообще, если еразить все елементы, зачем clear бы тогда вызвать?
Ну а если, скажем, мэйн имеет вид:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
int main()
{
 
node *a = new node;
node *b = new node;
node *c = new node(&a, &b);
 
//....
 
delete c;
 
//тут c больше нигде не используется, а a и b используются
 
delete a;
delete b;
 
return 0;
}
Тут будет утечка, если использовать деструктор вида:
C++
1
2
3
4
5
node::~node()
{
    delete a;
    delete b;
}
?

просто если прописать delete в деструкторе для элементов вектора, я объектами a и b же после удаления с пользоваться не смогу?
Bers
Заблокирован
10.11.2011, 23:39     Чтобы не было утечек памяти #11
Здесь налицо архитектурная ошибка.

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
int main()
{
node *a = new node;
node *b = new node;
node *c = new node(&a, &b);  //кто владелец данных?
//....
delete c;  //мы можем убить любой объект. 
              //А объект в этот момент может держать
              // указатели на другие себеподобные объекты.
              // Может получится ситуация, когда объект 
              //будит держать ссылки на уже убитые объекты. 
              //Это может привести к печальным последствиям.
 
//тут c больше нигде не используется, а a и b используются
delete a;  //А если объект с считает себя владельцем 
               //собственных данных, и попытается сделать 
               //им delete в своём диструкторе? 
               //Не получится двойного delete одному 
               //участку памяти?
delete b;
return 0;
}
Нарушение инкапсуляции. Класс не в состоянии обеспечить безопасность собственных данных.

Это значит, что подобная конструктива - мина замедленного действия, которая при любых раскладах может рвануть в любой момент.

1. разработчик класса не установил четких правил владения данными. Не понятно, кто является владельцем данных - указатели извне класса, или указатели изнутри класса?

2. Отсутствует разделение ответственности между классом и вызывающей стороной за работоспособность процесса.

3. Если владелец данных - класс, то наружная сторона не должна никаким образом иметь указатели на внутренние данные класса.

Иначе, считай , что уже имеем нарушение инкапсуляции: данные ничем никак не защищены, а наружная сторона сможет сделать с ними все что угодно. Например сделать им delete.
Svinina
5 / 5 / 0
Регистрация: 28.11.2010
Сообщений: 81
10.11.2011, 23:50  [ТС]     Чтобы не было утечек памяти #12
Bers, так что, получается вообще нельзя использовать указатели на класс внутри этого класса? Ведь в общем случае указанные тобой проблемы возникнут в любом случае и никак от них не избавиться?
Bers
Заблокирован
10.11.2011, 23:58     Чтобы не было утечек памяти #13
Цитата Сообщение от Svinina Посмотреть сообщение
Bers, так что, получается вообще нельзя использовать указатели на класс внутри этого класса? Ведь в общем случае указанные тобой проблемы возникнут в любом случае и никак от них не избавиться?
Это же с++, можно все. И исправить в большинстве случаев тоже всегда все можно)

Вам нужно определиться: кто за какие данные отвечает. В первую очередь.

Например: "класс может хранить указатели на себе подобные объекты, но не является их владельцем. Поэтому, он не будит освобождать данные по этим указателям".

В этом случае, в диструкторе класса вектор класса только тупо делает clear() и больше ничего.

Или так: "Класс принимает право владения объектом, на который указывает пришедший к нему указатель". В этом случае, класс запоминает где лежит объект, а пришедший указатель обнуляет. Теперь у вызывающей стороны будет нулевой указатель. Она ничего не сможет с ним сделать. А класс, принявший право владения объектом должен будит отвечать за корректное уничтожение этого объекта (пробежать по всему вектору, и сделать delete каждому элементу)

Короче говоря, сделать можно как угодно. Можно вообще через интеллектуальные указатели замутить. Зависит от задачи, и от самого программиста. Главное - что бы было четкое разделение ответственности и прав владения между классом и вызывающей стороной.
Svinina
5 / 5 / 0
Регистрация: 28.11.2010
Сообщений: 81
11.11.2011, 00:08  [ТС]     Чтобы не было утечек памяти #14
Например: "класс может хранить указатели на себе подобные объекты, но не является их владельцем. Поэтому, он не будит освобождать данные по этим указателям".

В этом случае, в диструкторе класса вектор класса только тупо делает clear() и больше ничего.
А как в таком случае победить это?
C++
1
2
3
4
5
6
delete c;  //мы можем убить любой объект. 
              //А объект в этот момент может держать
              // указатели на другие себеподобные объекты.
              // Может получится ситуация, когда объект 
              //будит держать ссылки на уже убитые объекты. 
              //Это может привести к печальным последствиям.
И еще, если clear в деструкторе не выполнить, указатели лежащие в нем так и будут в памяти болтаться образуя утечку?
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
11.11.2011, 00:31     Чтобы не было утечек памяти
Еще ссылки по теме:
Литература с++: чтобы было больше алгоритмов и много задач C++
C++ Как сделать, чтобы в char было hex число
C++ Как правильнее проинициализировать char's, чтобы не было мусора?
Задать условие, чтобы нельзя было ввести букву C++
C++ Как сделать, чтобы можно было не однократно вводить значения?

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

Или воспользуйтесь поиском по форуму:
Bers
Заблокирован
11.11.2011, 00:31     Чтобы не было утечек памяти #15
Цитата Сообщение от Svinina Посмотреть сообщение
А как в таком случае победить это?
Это правильный вопрос. Если класс не является владельцем объектов, значит он не контролирует время жизни этих объектов.

Но он хранит указатели на них не просто так, а для того, что бы иметь возможность обратиться через них к этим объектам.
И поэтому, ему очень важно иметь возможность узнать - а эти объекты вообще ещё живы?

Как это можно сделать? Способов много. Опять таки, зависит от конкретной задачи.
Один из способов - использовать не обычные указатели, а "интеллектуальные" указатели.
Что это такое, как они работают, и как их можно применять - узнайте у гугла.
Если будит потом ещё что-то непонятно - спрашивайте.

Но лично я стараюсь по возможности не прибегать к услугам интеллектуальных указателей.
Я бы скорее всего использовал что то вроде вот такого алгоритма:

1. При создании объекта, он получает знание о том, где лежит его "регистрационный массив данных". И тут же, при создании, он регистрирует свой собственный указатель в этом регистрационном массиве.

2. При уничтожении, объект в своем диструкторе удаляет запись о себе из этого регистрационного массива.

3. Таким образом, любой объект, зная где лежит регистрационный массив, в любой момент времени может получить данные обо всех "живых" себе подобных объектах.

4. Очень важно гарантировать, что регистрационный массив не будит уничтожен прежде, чем подохнет последний из объектов, которые его эксплуатируют (см "интеллектуальные указатели")

5. Если по задаче "регистрационный массив" должен быть только один на все объекты класса, то можно сделать его "статическим данным-членом" (см "статические данные-члены класса").


Цитата Сообщение от Svinina Посмотреть сообщение
И еще, если clear в деструкторе не выполнить, указатели лежащие в нем так и будут в памяти болтаться образуя утечку?
Когда вы делаете вектору метод clear() то, вектор полностью освобождает свою память.
То есть, он вызывает диструкторы всем элементам, которые содержит, а потом полностью удаляет память, которую эти элементы занимали.

Если вектор содержит только указатели - то память, которую занимали эти указатели будит освобождена. Но! Освобождена будит память, которую занимали сами указатели. А память, на которую указывали эти указатели так и останется неосвобождённой.


Добавлено через 1 минуту
Цитата Сообщение от Svinina Посмотреть сообщение
И еще, если clear в деструкторе не выполнить, указатели лежащие в нем так и будут в памяти болтаться образуя утечку?
Вообще, когда у объекта-хозяина закончится время жизни, то будут автоматически разрушены все его данные-члены, созданные на стеке. Для них автоматически будут вызваны ихние диструкторы.

У вектора диструктор вызывает метод clear() Таким образом, при разрушении, вектор сам автоматически чистит за собой.
Yandex
Объявления
11.11.2011, 00:31     Чтобы не было утечек памяти
Ответ Создать тему
Опции темы

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