Страницы

Поиск по вопросам

понедельник, 4 марта 2019 г.

Утечка памяти в перегрузке бинарных операторов

Создаю класс для работы со множествами, для расчет кол-ва тиков clock() прогоняю одну и ту же операцию N (const) раз. В итоге происходит огромная утечка памяти. Возможно дело в том, что в бинарных операциях & и | я создаю новый экземпляр класса с помощью дин. памяти каждую итерацию цикла. Но как освободить динамическую память в таком случае?
#include "stdafx.h" #include #include #include #include using namespace std;
const unsigned int N = 100000;
//Массив символов class Set { int n; //Мощность множества static int U; //Мощность универсума char litera; //Обозначение множества A,B,C,D и так далее char* universe; //Указатель на множество public: Set(char _litera); ~Set(); Set(); void print(); int power() { return n; } //Операции над множествами Set& operator & (const Set& B) const; Set& operator ~ () const; //Операторы копирования и присваивания с переносом Set(Set &); Set& operator = (Set& B); };
Set::Set() : litera('0'), n(0), universe(new char[U + 1]) { //cout << "Создание пустого множества " << litera << " = []
"; universe[0] = '\0'; }; Set ::~Set() { //cout << "Удаление множества " << litera << '
'; delete[] universe; } Set:: Set(char _litera): litera(_litera),n(0),universe(new char[U+1]) { for (int i = 0; i < U; i++) { if (rand() % 2) { universe[n++] = '0' + i; } } universe[n] = '\0'; //cout << "Создание множества " << litera << " = [" << universe << "]
"; } void Set::print() { cout << litera << " = [" << universe << "]" << '
'; } //Операции над множествами Set& Set:: operator & (const Set& B) const { Set *C = new Set; for (int i = 0; i < n; i++) { for (int j = 0; j < B.n; j++) { if (universe[i] == B.universe[j]) C->universe[C->n++] = universe[i]; } } C->universe[C->n] = 0; //cout << "Результат пересечения множества " << litera << " = [" << universe << "]" // << " со множеством " << B.litera << " = [" << B.universe << "]" << " => " << C->litera << " = [" << C->universe << "]
"; return *C; } Set& Set:: operator ~ () const { Set *C = new Set; for (char ch = '0'; ch <= '9'; ch++) { bool flag = true; for (int j = 0; j < n; j++) { if (ch == universe[j]) { flag = false; break; } } if (flag) C->universe[C->n++] = ch; } C->universe[C->n] = '\0'; //cout << "Результат инверсии множества " << litera << " = [" << universe << "]" // << " => " << C->litera << " = [" << C->universe << "]
"; return *C; } //Операторы перегрузки и присваивания с переносом Set:: Set(Set & B): litera(B.litera), n(B.n), universe(B.universe) { //cout << "Конструктор копирования множества c переносом " << B.litera << '
'; B.universe = NULL; } Set& Set:: operator = (Set& B) { //cout << "Конструктор присваивания множества с переносом" << B.litera << '
'; if (this != &B) { n = B.n; universe = B.universe; litera = 'R'; B.universe = NULL; } return *this; }
//Поместить после include int Set::U = 10; //Мощность универсума для десятичных цифр
int main() { setlocale(LC_ALL, ""); srand(time(NULL)); time_t start, stop; Set A('A'), B('B'), C('C'), D('D'), E; A.print(); B.print(); C.print(); D.print(); system("pause"); //Обработка множеств start = clock(); for (int i = 0; i < N; i++) E = ((A & ~(B & C)) & ~D); stop = clock(); //Вывод итогового множества E.print(); //Вывод средней мощности и времени cout << "Average power = " << (A.power() + B.power() + C.power() + D.power() + E.power()) / 5 << '
'; cout << "Time = " << stop - start << '/' << N << '
'; system("pause"); return 0; }


Ответ

У Вас в "операторах" ~ и & выделяется динамическая память:
Set& Set:: operator ~ () const { Set *C = new Set;
Но она нигде не освобождается. Сразу возникает вопрос, а зачем Вам понадобилась здесь динамическое выделение памяти? Может всё-таки переделать без динамической памяти?
Set Set:: operator & (const Set& B) const { Set C; //работа с C return C; } Set Set:: operator ~ () const { Set C; //работа с C return C; }
(объявления тоже необходимо переделать под новые условия). Во-первых, избавились от динамической аллокации, во-вторых, нормальный компилятор применит NRVO, устранив, тем самым, копирование в возвращаемое значение.
Также стоит учесть, что Ваши operator= и конструктор копирования повторяют печальную судьбу auto_ptr, когда присваивание и копирование захватывает ресурсы исходного объекта. Стоило бы сделать дополнительно перемещающие версии, предоставив пользователю больше средств.

Комментариев нет:

Отправить комментарий