Форум программистов, компьютерный форум, киберфорум
Наши страницы
С++ для начинающих
Войти
Регистрация
Восстановить пароль
 
Рейтинг 4.50/6: Рейтинг темы: голосов - 6, средняя оценка - 4.50
Whitelake
0 / 0 / 0
Регистрация: 29.10.2014
Сообщений: 8
#1

Утечки памяти при использовании new/delete для двумерных массивов

29.10.2014, 15:04. Просмотров 1042. Ответов 10
Метки нет (Все метки)

Добрый день.

Суть в том, что есть несколько функций, получающих на вход и возвращающих двумерные массивы. Реализация передачи массивов ясна из кода ниже. Функции вызываются одна из-под другой.

Отслеживание утечек памяти делаю с помощью _CrtDumpMemoryLeaks() перед завершением в main.
Утечки обнаруживаются в местах, где выделяется память под массив, который потом будет заполняться вызовом другой функции. В приведённом коде, например, ругнётся на строчки 3 и 6 файла F0.cpp.

main.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
int main (void)
{
    double **U = new double*[9];
    for(i = 0; i < 9; i++)
    {
        U[i] = new double[N];
    }
 
    // Делаем что-то с U
 
    while ( //условие )
    {
        U = F0(U);      
    }
 
    _CrtDumpMemoryLeaks();
 
    for(i=0; i<9; i++)
    {
        delete []U[i]; U[i] = 0;
    }
    delete []U; U = 0;
 
    return 0;
}
F0.cpp
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
double **F0(double **U)
{
    double **L = new double*[9];
    for(i = 0; i < 9; i++)
    {
        L[i] = new double[N];
    }
 
    L = F1(U);
    U = //преобразования L
 
    for(i=0; i<9; i++)
    {
        delete []L[i]; L[i] = 0;
    }
    delete []L; L = 0;
 
    return U;
}
F1.cpp
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
double **F1(double **U)
{
    double **L = new double*[9];
    for(i = 0; i < 9; i++)
    {
        L[i] = new double[N];
    }
 
    //...
 
    return L;
 
    for(i=0; i<9; i++)
    {
        delete []L[i]; L[i] = 0;
    }
    delete []L; L = 0;
}
В целом, всё работает корректно, но при достаточно длинном цикле в main, через некоторое время вылетает с ошибкой типа "Unhandled exception at 0x76e7c42d in 123.exe: Microsoft C++ exception: std::bad_alloc at memory location 0x003be460..".
Ошибка, вероятно, в выделении/освобождении памяти при работе с вложенными функциями, но ничего в голову не приходит. Подскажите, пожалуйста.

Заранее благодарен.
0
Лучшие ответы (1)
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
29.10.2014, 15:04
Ответы с готовыми решениями:

Динамическое выделение памяти. Использование функций для обработки двумерных массивов
не понимаю что делаю хотя задание такое 1.2. Постановка задачи Задача 1....

Какие есть виды массивов (кроме одномерных, двумерных и двумерных ступенчатых массивов)?
Какие есть виды массивов (кроме одномерных, двумерных и двумерных ступенчатых...

Ошибка при использовании new[] / delete[]
Здравствуйте. Пишу учебную программу, моделирующую движение лифта (если кто...

Ошибка при использовании delete
И снова здравствуйте! Пишу раз третий.Я уже готов убицца ап сцену изза этого...

Ошибка при использовании оператора delete в Visual Studio 2010
Изучаю указатели в C++. Есть следующий код: #include &lt;iostream&gt; #include...

10
Tulosba
:)
Эксперт С++
4747 / 3241 / 497
Регистрация: 19.02.2013
Сообщений: 9,046
29.10.2014, 15:27 #2
в F0.cpp в 9 строке теряется доступ (остается висеть в памяти) к тому что было выделено в 3 и 6 строках.
0
Whitelake
0 / 0 / 0
Регистрация: 29.10.2014
Сообщений: 8
29.10.2014, 18:29  [ТС] #3
Цитата Сообщение от Tulosba Посмотреть сообщение
в F0.cpp в 9 строке теряется доступ (остается висеть в памяти) к тому что было выделено в 3 и 6 строках.
Спасибо.
А как в таком случае вернуть результат выполнения F1 в F0, так чтобы потом эту память очистить?
0
alsav22
5441 / 4836 / 831
Регистрация: 04.06.2011
Сообщений: 13,587
29.10.2014, 18:48 #4
Смысл, вот этого куска, в чём?

Цитата Сообщение от Whitelake Посмотреть сообщение
C++
1
2
3
4
5
6
7
return L;
for(i=0; i<9; i++)
{
    delete []L[i]; L[i] = 0;
}
delete []L; L = 0;
}
0
Whitelake
0 / 0 / 0
Регистрация: 29.10.2014
Сообщений: 8
29.10.2014, 18:59  [ТС] #5
Не нужно освобождать память, выделенную под возвращаемую переменную? При return она освобождается автоматически?
На самом деле, подобные конструкции -- результат попыток решить проблему методом тыка, ибо всё что мог уже попробовал, а от утечек избавиться не удаётся.

Вы уж не судите строго: переношу код на практически новый для меня язык.
0
alsav22
5441 / 4836 / 831
Регистрация: 04.06.2011
Сообщений: 13,587
29.10.2014, 19:05 #6
Цитата Сообщение от Whitelake Посмотреть сообщение
Не нужно освобождать память, выделенную под возвращаемую переменную?
Если return стоит перед освобождением памяти, то как туда код сможет дойти?

Добавлено через 3 минуты
Цитата Сообщение от Whitelake Посмотреть сообщение
На самом деле, подобные конструкции -- результат попыток решить проблему методом тыка, ибо всё что мог уже попробовал, а от утечек избавиться не удаётся.
Проблема, по-моему, в том, что код не продуман. Непонятно, зачем там, вообще, эти вызовы функций с передачами массивов? Без них, разве, нельзя обойтись? Задача какая?
0
Whitelake
0 / 0 / 0
Регистрация: 29.10.2014
Сообщений: 8
29.10.2014, 19:16  [ТС] #7
Вызовы функций с передачами массивов нужны, так как очень желательно сохранить структуру программы, написанной на Фортране... Наверное, это не очень правильно, но это уже вопрос идеологического плана.
А проблему хотелось бы решить в рамках существующей реализации: нужно правильно выделить память под массив, записать в него результат выполнения функции и освободить память.
0
alsav22
5441 / 4836 / 831
Регистрация: 04.06.2011
Сообщений: 13,587
29.10.2014, 20:38 #8
Цитата Сообщение от Whitelake Посмотреть сообщение
А проблему хотелось бы решить в рамках существующей реализации: нужно правильно выделить память под массив, записать в него результат выполнения функции и освободить память.
Чтобы конкретное что-либо посоветовать, нужно больше кода видеть. По выложенным кускам мало что понятно.

Добавлено через 1 час 15 минут
А общий совет: передавайте по ссылке, тогда и возвращать ничего не нужно.
0
Whitelake
0 / 0 / 0
Регистрация: 29.10.2014
Сообщений: 8
29.10.2014, 21:01  [ТС] #9
Цитата Сообщение от alsav22 Посмотреть сообщение
А общий совет: передавайте по ссылке, тогда и возвращать ничего не нужно.
Это было бы хорошо, но что-то я совсем не представляю, как сделать передачу по ссылке двумерного массива...
0
alsav22
5441 / 4836 / 831
Регистрация: 04.06.2011
Сообщений: 13,587
29.10.2014, 22:26 #10
Лучший ответ Сообщение было отмечено Whitelake как решение

Решение

Цитата Сообщение от Whitelake Посмотреть сообщение
как сделать передачу по ссылке двумерного массива...
Так же, как одномерного.

Добавлено через 58 минут
Если в функциях действия только с содержимым массива:
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
#include <iostream>
using namespace std;
 
void F0(double **U);
void F1(double **U);
 
int N = 3;
int M = 4;
 
int main (void)
{
    double **U = new double*[N];
    for(int i = 0; i < N; i++)
    {
        U[i] = new double[M];
        for (int j = 0; j < M; ++j)
            U[i][j] = j;
    }
    
    cout << "main" << endl; 
    for(int i = 0; i < N; i++)
    {
        for (int j = 0; j < M; ++j)
           cout << U[i][j] << ' ';
        cout << endl;
    }
    cout << endl;
    
    F0(U);
    
    cout << "main after F0" << endl; 
    for(int i = 0; i < N; i++)
    {
        for (int j = 0; j < M; ++j)
           cout << U[i][j] << ' ';
        cout << endl;
    }
    cout << endl;
    
    for(int i=0; i<N; i++)
        delete [] U[i]; 
    delete [] U;
   
    cout << _CrtDumpMemoryLeaks() << endl;
    return 0;
}
 
void F0(double **U)
{
    for(int i = 0; i < N; i++)
        for (int j = 0; j < M; ++j)
           ++(U[i][j]);
        
    cout << "F0" << endl;
    for(int i = 0; i < N; i++)
    {
        for (int j = 0; j < M; ++j)
           cout << U[i][j] << ' ';
        cout << endl;
    }
    cout << endl;
    
    F1(U);
    
    cout << "F0 after F1" << endl;
    for(int i = 0; i < N; i++)
    {
        for (int j = 0; j < M; ++j)
           cout << U[i][j] << ' ';
        cout << endl;
    }
    cout << endl;
}
 
void F1(double **U)
{
    for(int i = 0; i < N; i++)
        for (int j = 0; j < M; ++j)
           ++(U[i][j]);
}
Если действия и с указателем (перевыделение памяти):
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
#include <iostream>
using namespace std;
 
void F0(double **&U);
void F1(double **&U);
 
int N = 3;
int M = 4;
 
int A = 5;
int B = 6;
 
int main (void)
{
    double **U = new double*[N];
    for(int i = 0; i < N; i++)
    {
        U[i] = new double[M];
        for (int j = 0; j < M; ++j)
            U[i][j] = j;
    }
    
    cout << "main" << endl; 
    for(int i = 0; i < N; i++)
    {
        for (int j = 0; j < M; ++j)
           cout << U[i][j] << ' ';
        cout << endl;
    }
    cout << endl;
    
    F0(U);
    
    cout << "main after F0" << endl; 
    for(int i = 0; i < A; i++)
    {
        for (int j = 0; j < B; ++j)
           cout << U[i][j] << ' ';
        cout << endl;
    }
    cout << endl;
    
    for(int i=0; i<A; i++)
        delete [] U[i]; 
    delete [] U;
   
    cout << _CrtDumpMemoryLeaks() << endl;
    return 0;
}
 
void F0(double **&U)
{
    for(int i = 0; i < N; i++)
        for (int j = 0; j < M; ++j)
           ++(U[i][j]);
    
    cout << "F0" << endl;   
    for(int i = 0; i < N; i++)
    {
        for (int j = 0; j < M; ++j)
           cout << U[i][j] << ' ';
        cout << endl;
    }
    cout << endl;
    
    F1(U);
    
    cout << "F0 after F1" << endl;
    for(int i = 0; i < A; i++)
    {
        for (int j = 0; j < B; ++j)
           cout << U[i][j] << ' ';
        cout << endl;
    }
    cout << endl;
}
 
void F1(double **&U)
{
    for(int i = 0; i < N; i++)
        delete [] U[i]; 
    delete [] U;
    
    U = new double*[A];
    for(int i = 0; i < A; i++)
    {
        U[i] = new double[B];
        for (int j = 0; j < B; ++j)
            U[i][j] = j;
    }
}
Добавлено через 16 минут
Или так:
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
#include <iostream>
using namespace std;
 
struct size
{
    int n;
    int m;
};
 
size F0(double **&U);
size F1(double **&U);
 
int N = 3;
int M = 4;
 
int main (void)
{
    double **U = new double*[N];
    for(int i = 0; i < N; i++)
    {
        U[i] = new double[M];
        for (int j = 0; j < M; ++j)
            U[i][j] = j;
    }
    
    cout << "main" << endl; 
    for(int i = 0; i < N; i++)
    {
        for (int j = 0; j < M; ++j)
           cout << U[i][j] << ' ';
        cout << endl;
    }
    cout << endl;
    
    size s = F0(U);
    cout << "main after F0" << endl; 
    for(int i = 0; i < s.n; i++)
    {
        for (int j = 0; j < s.m; ++j)
           cout << U[i][j] << ' ';
        cout << endl;
    }
    cout << endl;
    
    for(int i = 0; i < s.n; i++)
        delete [] U[i]; 
    delete [] U;
   
    cout << _CrtDumpMemoryLeaks() << endl;
    return 0;
}
 
size F0(double **&U)
{
    for(int i = 0; i < N; i++)
        for (int j = 0; j < M; ++j)
           ++(U[i][j]);
    
    cout << "F0" << endl;   
    for(int i = 0; i < N; i++)
    {
        for (int j = 0; j < M; ++j)
           cout << U[i][j] << ' ';
        cout << endl;
    }
    cout << endl;
    
    size s = F1(U);
    
    cout << "F0 after F1" << endl;
    for(int i = 0; i < s.n; i++)
    {
        for (int j = 0; j < s.m; ++j)
           cout << U[i][j] << ' ';
        cout << endl;
    }
    cout << endl;
 
    return s;
}
 
size F1(double **&U)
{
    for(int i = 0; i < N; i++)
        delete [] U[i]; 
    delete [] U;
 
    size s = {5, 6};
    
    U = new double*[s.n];
    for(int i = 0; i < s.n; i++)
    {
        U[i] = new double[s.m];
        for (int j = 0; j < s.m; ++j)
            U[i][j] = j;
    }
 
    return s;
}
1
Whitelake
0 / 0 / 0
Регистрация: 29.10.2014
Сообщений: 8
30.10.2014, 00:29  [ТС] #11
alsav22, большое спасибо за помощь.
Я переделал всё так, чтобы все "вложенные" функции были void, то есть преобразовывали получаемый массив в соответствии с первым из предложенных вариантов. Нужно было сразу об этом задуматься: задача такова, что все передаваемые и возвращаемые массивы имеют одинаковые размерности.
С памятью теперь всё нормально.

Ещё раз благодарю.
0
30.10.2014, 00:29
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
30.10.2014, 00:29

new и delete при освобождении памяти
Здравствуйте. Скажите, пожалуйста что я неправильно делаю. При освобождении...

Ошибка при освобождении памяти (delete)
Здравствуйте! Есть массив lines, созданный вот так : int *line = new int ; ...

Использование двумерных массивов при обращении к объектам классов
Проблема в программе, если будет нужно, напишу подробности программы....


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

Или воспользуйтесь поиском по форуму:
11
Ответ Создать тему
Опции темы

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