Страницы

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

суббота, 11 января 2020 г.

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

#cpp #visual_studio #visual_cpp #память


Создаю класс для работы со множествами, для расчет кол-ва тиков 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 << " = []\n";
    universe[0] = '\0';
};
Set ::~Set() {
    //cout << "Удаление множества " << litera << '\n';
    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 << "]\n";
}
void Set::print() {
    cout << litera << " = [" << universe << "]" << '\n';
}
//Операции над множествами
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 << "]\n";
    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 << "]\n";
    return *C;
}
//Операторы перегрузки и присваивания с переносом
Set:: Set(Set & B): litera(B.litera), n(B.n), universe(B.universe) {
    //cout << "Конструктор копирования множества c переносом " << B.litera << '\n';
    B.universe = NULL;
}
Set& Set:: operator = (Set& B) {
    //cout << "Конструктор присваивания множества с переносом" << B.litera << '\n';
    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 << '\n';
    cout << "Time = " << stop - start << '/' << N << '\n';
    system("pause");
    return 0;
}

    


Ответы

Ответ 1



У Вас в "операторах" ~ и & выделяется динамическая память: 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, когда присваивание и копирование захватывает ресурсы исходного объекта. Стоило бы сделать дополнительно перемещающие версии, предоставив пользователю больше средств.

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

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