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

Есть ли утечка памяти в этом случае? - C++

Восстановить пароль Регистрация
 
 
NonCFist
0 / 0 / 0
Регистрация: 01.06.2013
Сообщений: 12
01.06.2013, 19:20     Есть ли утечка памяти в этом случае? #1
_Доброго денёчка всем. Прохожу тему на указатели и ссылки. Делаю упражнение на тему "написать программу, вызывающую утечку памяти". Смысл идеи "учись на ошибках и запомни как делать не нуна, а то будет ай-ай-ай".
В книге приведён пример такой логической ошибки, когда в функции выполняется создание экземпляра класса, для которого оператором new в функции выделяется память. Затем ссылка на объект передаётся в main для дальнейших издевательств..
_Ну вот я нечто в этом роде и написал. А потом малость подправил, и теперь не уверен, что в моем коде есть утечка памяти. Помогите, корифеи, Христа ради.

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
 // Логическая ошибка, приводящая к утечке памяти.
#include <iostream>
using namespace std;
 
class Detail
{
public: Detail (int length, int width);
        ~Detail ();
        int GetLength() const { return itsLength; }
        int GetWidth() const { return itsWidth; }
        void SetLength (int length) { itsLength = length; }
        void SetWidth (int width) { itsWidth = width; }
private:
    int itsLength;
    int itsWidth;
};
 
Detail::Detail (int length, int width)
{
    cout << " Calling constructor...\n";
    itsLength = length;
    itsWidth = width;
}
 
Detail::~Detail()
{
    cout << " Calling destructor...\n";
}
 
Detail & MakeDetail ();
 
int main()
{
    cout << "\n\n";
    Detail Det1(600, 510);
    cout << " Det.1 Length: " << Det1.GetLength() << " mm.\n";
    cout << " Det.1 Width: " << Det1.GetWidth() << " mm.\n";
    cout << "\n";
    Detail Det2 = MakeDetail();  
    cout << " Det.2 Length: " << Det2.GetLength() << " mm.\n";
    cout << " Det.2 Width: " << Det2.GetWidth() << " mm.\n";
    cout << "\n\n";
    system ("pause");
    return 0;
}
 
Detail & MakeDetail ()
{
    cout << " Calling MakeDetail...\n";
    Detail * NewDetail = new Detail (0, 0);
    NewDetail->SetLength(704);
    NewDetail->SetWidth(510);
    return *NewDetail;
}
Output:

Calling constructor...
Det.1 Length: 600 mm.
Det.1 Width: 510 mm.

Calling MakeDetail...
Calling constructor...
Det.2 Length: 704 mm.
Det.2 Width: 510 mm.


Для продолжения нажмите любую клавишу . . .
Caling destructor...
Caling destructor...

Деструктор, как видите, вызывается дважды. Или таки память от *NewDetail не очищена?
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
01.06.2013, 19:20     Есть ли утечка памяти в этом случае?
Посмотрите здесь:

Утечка памяти C++
Утечка памяти?! C++
C++ Утечка памяти
Есть ли утечка памяти? C++
Утечка памяти C++
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
Croessmah
Модератор
Эксперт С++
 Аватар для Croessmah
11816 / 6795 / 769
Регистрация: 27.09.2012
Сообщений: 16,867
Записей в блоге: 2
Завершенные тесты: 1
01.06.2013, 19:33     Есть ли утечка памяти в этом случае? #2
Сделайте еще конструктор копий и посмотрите на результаты
alex_x_x
бжни
 Аватар для alex_x_x
2441 / 1646 / 84
Регистрация: 14.05.2009
Сообщений: 7,163
01.06.2013, 19:33     Есть ли утечка памяти в этом случае? #3
Сообщение было отмечено автором темы, экспертом или модератором как ответ
Хах, третий раз переписываю ответ
Скорее всего проблема есть, так как стековые и объекты из кучи разрушаются по разному, но тут у меня сомнения насчет ссылки: то есть я не уверен, что оно должно быть закорапчено, но delete вызван не будет в любом случае, те утечка есть

На самом деле здесь идеально бы пошел scoped_ptr
Croessmah
Модератор
Эксперт С++
 Аватар для Croessmah
11816 / 6795 / 769
Регистрация: 27.09.2012
Сообщений: 16,867
Записей в блоге: 2
Завершенные тесты: 1
01.06.2013, 19:34     Есть ли утечка памяти в этом случае? #4
Цитата Сообщение от NonCFist Посмотреть сообщение
Или таки память от *NewDetail не очищена?
После завершения программы ОС сама все почистит, но не хорошо на это опираться.
alex_x_x
бжни
 Аватар для alex_x_x
2441 / 1646 / 84
Регистрация: 14.05.2009
Сообщений: 7,163
01.06.2013, 19:35     Есть ли утечка памяти в этом случае? #5
Цитата Сообщение от Croessmah Посмотреть сообщение
Сделайте еще конструктор копий и посмотрите на результаты
Здесь ссылка, то есть копирования нет
Croessmah
Модератор
Эксперт С++
 Аватар для Croessmah
11816 / 6795 / 769
Регистрация: 27.09.2012
Сообщений: 16,867
Записей в блоге: 2
Завершенные тесты: 1
01.06.2013, 19:38     Есть ли утечка памяти в этом случае? #6
Сообщение было отмечено автором темы, экспертом или модератором как ответ
Цитата Сообщение от alex_x_x Посмотреть сообщение
Здесь ссылка, то есть копирования нет
Вот тут есть:
C++
1
Detail Det2 = MakeDetail();
ибо Det2 не ссылка.
gray_fox
What a waste!
 Аватар для gray_fox
1244 / 1127 / 53
Регистрация: 21.04.2012
Сообщений: 2,350
Завершенные тесты: 3
01.06.2013, 19:39     Есть ли утечка памяти в этом случае? #7
Цитата Сообщение от alex_x_x Посмотреть сообщение
Здесь ссылка, то есть копирования нет
Здесь должно быть:
Цитата Сообщение от NonCFist Посмотреть сообщение
C++
1
Detail Det2 = MakeDetail();
NonCFist
0 / 0 / 0
Регистрация: 01.06.2013
Сообщений: 12
01.06.2013, 20:01  [ТС]     Есть ли утечка памяти в этом случае? #8
_Т. е. утечка есть, так как явно эта выделенная память в программе не очищается, да? Спасибо, значит я всё правильно натупил.

Добавлено через 3 минуты

Не по теме:

_Я пока ещё не шибко здорово усвоил тонкости передачи и возврата объектов с помощью ссылок. Вот пока на кошках тренируюсь.

Croessmah
Модератор
Эксперт С++
 Аватар для Croessmah
11816 / 6795 / 769
Регистрация: 27.09.2012
Сообщений: 16,867
Записей в блоге: 2
Завершенные тесты: 1
01.06.2013, 20:10     Есть ли утечка памяти в этом случае? #9
Цитата Сообщение от NonCFist Посмотреть сообщение
_Т. е. утечка есть, так как явно эта выделенная память в программе не очищается, да?
Да, есть. После этого
C++
1
Detail Det2 = MakeDetail();
память, выделенная в MakeDetail остается висеть и ничто на неё не указывает, а значит нет возможности её освободить.

Вот такой main:
C++
1
2
3
4
5
6
int main()
{
    while(true)
         MakeDetail();
    return 0;
}
вот такие результаты в диспетчере задач:
Есть ли утечка памяти в этом случае?
alex_x_x
бжни
 Аватар для alex_x_x
2441 / 1646 / 84
Регистрация: 14.05.2009
Сообщений: 7,163
01.06.2013, 20:12     Есть ли утечка памяти в этом случае? #10
Croessmah, йеп, да с той стороны то не ссылка, но утечка в любом случае получается
NonCFist
0 / 0 / 0
Регистрация: 01.06.2013
Сообщений: 12
01.06.2013, 20:19  [ТС]     Есть ли утечка памяти в этом случае? #11
Спасибо всем за ответы. Буду курить дальше.
taras atavin
Ушёл с форума.
 Аватар для taras atavin
3569 / 1752 / 91
Регистрация: 24.11.2009
Сообщений: 27,619
01.06.2013, 20:29     Есть ли утечка памяти в этом случае? #12
А зачем вообще нужна память, на которую ни что не указывает? Зачем её было выделять?
Croessmah
Модератор
Эксперт С++
 Аватар для Croessmah
11816 / 6795 / 769
Регистрация: 27.09.2012
Сообщений: 16,867
Записей в блоге: 2
Завершенные тесты: 1
01.06.2013, 20:30     Есть ли утечка памяти в этом случае? #13
Цитата Сообщение от taras atavin Посмотреть сообщение
Зачем её было выделять?
вот ответ:
Цитата Сообщение от NonCFist Посмотреть сообщение
Прохожу тему на указатели и ссылки. Делаю упражнение на тему "написать программу, вызывающую утечку памяти".
NonCFist
0 / 0 / 0
Регистрация: 01.06.2013
Сообщений: 12
01.06.2013, 21:38  [ТС]     Есть ли утечка памяти в этом случае? #14
Detail & Det2 = MakeDetail();

Смыл этой строки мне непонятен... Это значит что я создаю ссылку на тип Detail и присваиваю этой ссылке другую ссылку? Поэтому я убрал амперсант перед Det2.
Croessmah
Модератор
Эксперт С++
 Аватар для Croessmah
11816 / 6795 / 769
Регистрация: 27.09.2012
Сообщений: 16,867
Записей в блоге: 2
Завершенные тесты: 1
01.06.2013, 21:54     Есть ли утечка памяти в этом случае? #15
Цитата Сообщение от NonCFist Посмотреть сообщение
Поэтому я убрал амперсант перед Det2.
Убрали амперсанд - получили копирование и невозможность далее освободить память.
NonCFist
0 / 0 / 0
Регистрация: 01.06.2013
Сообщений: 12
01.06.2013, 22:05  [ТС]     Есть ли утечка памяти в этом случае? #16
Т.е. верно, что в случае

Detail & Det2 = MakeDetail();

означает

ссылка = ссылка? Ну да, можно потом на ссылку в левой части натравить указатель, а потом применить к указателю delete. Память свободна. А на что тогда будет ссылаться ссылка &Det2 ? Либерти сказал, чтобы я так никогда не обращался со ссылками, ибо грех.
_Да , и я про копирование не понял всё же. Можно пояснить?
Croessmah
Модератор
Эксперт С++
 Аватар для Croessmah
11816 / 6795 / 769
Регистрация: 27.09.2012
Сообщений: 16,867
Записей в блоге: 2
Завершенные тесты: 1
01.06.2013, 22:13     Есть ли утечка памяти в этом случае? #17
Цитата Сообщение от NonCFist Посмотреть сообщение
ссылка = ссылка?
Да. А так как возвращаемая ссылка ссылается на объект в выделенной динамически памяти, то и Det2 быдет ссылаться на тот же объект.
Цитата Сообщение от NonCFist Посмотреть сообщение
Память свободна. А на что тогда будет ссылаться ссылка &Det2 ?
Ссылка становиться не валидной, т.к. ссылается на объект, которого уже по сути нет. Использование такой ссылки - это UB

Цитата Сообщение от NonCFist Посмотреть сообщение
Либерти сказал, чтобы я так никогда не обращался со ссылками, ибо грех.
Как именно?

Цитата Сообщение от NonCFist Посмотреть сообщение
_Да , и я про копирование не понял всё же. Можно пояснить?
Ну если у Вас ссылка
C++
1
Detail & Det2 = MakeDetail();
то в Det2 будет скопирована возвращенная ссылка. А если без ссылки
C++
1
Detail Det2 = MakeDetail();
то Det2 - это уже объект, который будет построен на основе переданного(будет вызван конструктор копий).
Даную запись можно сделать так:
C++
1
Detail Det2(MakeDetail());
NonCFist
0 / 0 / 0
Регистрация: 01.06.2013
Сообщений: 12
01.06.2013, 22:24  [ТС]     Есть ли утечка памяти в этом случае? #18
Спасибы.
_Либерти сказал, чтобы в программе не было ссылок на ничто. Некорректно, это, говорит, не по фэншую и вообще грубая ошибка, которая при случае может вылиться в черт знает что.
OhMyGodSoLong
~ Эврика! ~
 Аватар для OhMyGodSoLong
1234 / 983 / 42
Регистрация: 24.07.2012
Сообщений: 2,002
02.06.2013, 01:28     Есть ли утечка памяти в этом случае? #19
/me шепчет: «Смарт-поинтеры».
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
02.06.2013, 14:43     Есть ли утечка памяти в этом случае?
Еще ссылки по теме:

C++ утечка памяти
C++ Утечка памяти
Есть ли утечка памяти в list C++

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

Или воспользуйтесь поиском по форуму:
IGPIGP
Комп_Оратор)
 Аватар для IGPIGP
6166 / 2895 / 282
Регистрация: 04.12.2011
Сообщений: 7,695
Записей в блоге: 3
02.06.2013, 14:43     Есть ли утечка памяти в этом случае? #20
А я согласен с alex_x_x в том, что ссылка на локально созданный, динамический объект не обязательно не валидна.
Ссылка - псевдоним переменной. Иногда говорят, что это указатель который всегда разыменовывается.
Классический пример возврата ссылки на локальную переменную:
C++
1
2
3
4
5
6
7
8
9
10
11
12
#include <iostream>
using namespace std;
//вот возврат ссылки на локальную стековую переменную
int& retInt(){int c=5;  return c;}
int main()
{
int& a=retInt();//
for(int i=0; i<1000; ++i)cout<<a<<endl;//чушь как и должно быть (стек освободился от переменной с, - её нет)
system("pause");
cout << endl;
return 0;
}
С псевдонимом вроде ясно, но что значит, что ссылка это указатель, который всегда разыменовывается? Это же иносказание. Я попробовал представить так:
Указатель при разыменовании не просто представляет значение переменной на которую указывает, он предоставляет имя переменной через которую предоставляется значение. Когда одной переменной присваивается разыменованный указатель, то промежуточный этап не важен и можно считать, что в переменную копируется значение по указателю. Другое дело когда разыменованный указатель присваивается ссылке. Пример:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>
using namespace std;
int main()
{
int a=123;//
int& b = a;//b - псевдоним a, адреса a и b совпадают
int* p=&a;
int& c = *p;//с - псевдоним a, адреса a и с совпадают, 
//но p лишь предоставил переменную a переменной c и от того жив ли он уже ничего не зависит!
p=0;//не важно какое у него значение, главное, чтобы не было явного освобождения (delete) по "старому" адресу (a)
cout<<a<<endl;//123
cout<<&a<<endl;
cout<<b<<endl;//123
cout<<&b<<endl;
cout<<c<<endl;//123
cout<<&c<<endl;
system("pause");
cout << endl;
return 0;
}
Пример с возвратом ссылки на динамический объект. Такой объект не имеет имени, но безымянная переменная создаётся. Указатель на неё,- на стеке и будет уничтожен, но она сама - (анонимная переменная), хоть и создаётся локально, но связана с динамическим объектом и обладает его временем жизни (? это на правах вопроса). Вернее может сказать, что всё что в ней описывает участок динамической памяти, остаётся жить, а имени нет и разрушать по сути нечего.
Во всяком случае похоже принимающая ссылка валидна:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
    
#include <iostream>
using namespace std;
int& MakeInt ();
int main()
{
int& a =  MakeInt ();
for(int i=0; i<1000; ++i)cout<<a<<endl;//всё живо (может цикл маловат?))
system("pause");
cout << endl;
return 0;
}
int& MakeInt ()
{    
    int* NewInt = new int (123);
    
    return *NewInt;
}
И напоследок этот же пример с попыткой показать, что разрушение локального указателя не освобождает память и ссылка им предоставляемая (безымянное имя)) живет после выхода из зоны видимости:
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
#include <iostream>
using namespace std;
int& MakeInt (int* ptrSpy);//передаём шпиёна
int main()
{
int* p=0;
int& a =  MakeInt (p);
cout<<"out just after NewInt() p= "<<p<<endl;//уже не указывает (NewInt уничтожен)
cout<<a<<endl;
cout<<&a<<endl;//а тут информация о адресе в дин. памяти есть (она никак не связана с жизнью указателя NewInt)
p=&a;//устанавливаем "на место"
delete p;//похоже a связана с памятью выделенной new при инициализации NewInt, посредством анонимной переменной которая на неё ссылается и не уничтожена
//так как память на которую она ссылается (динамическая же) не освобождена, при этом она получена разыменованием NewInt, но её время
//жизни определяется связанной с нею памятью, а не временем жизни указателя. То есть следующий оператор - обращение в никуда:
cout<<a<<endl;//так и есть. То есть, явное освобождение памяти и разрушение локальной переменной-указателя не одно и то же.
system("pause");
cout << endl;
return 0;
}
int& MakeInt (int* p)
{    
 int* NewInt = new int (123);
cout<<"in NewInt() NewInt= "<<NewInt<<endl;
 p=NewInt; 
 cout<<"in NewInt() p= "<<p<<endl;//указывает с NewInt на один адрес
    return *NewInt;
}
Вполне вероятно, что локальная созданная ссылка на динамический объект может реализовываться по-разному, во всяком случае, VS C++ демонстрирует её живучесть по сравнению с локальным указателем. Более того, предупреждения о возврате локальной ссылки не выдаёт, как это имеет место быть в первом примере, (то есть локально созданная и локально "обитающая", не одно и тоже?), как в самом первом случае, где всё предельно ясно: локальная переменная - ссылка - кирдык.
Yandex
Объявления
02.06.2013, 14:43     Есть ли утечка памяти в этом случае?
Ответ Создать тему
Опции темы

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