Почему не получается освободить память в деструкторе?

Как можно улучшить код класса, представляющего числа в виде массива из двухзначных чисел, а также оптимизировать его функции? Вот мой текущий код: <pre><code class="cpp">#include &lt;iostream&gt;
#include &lt;cstdlib&gt;
#include &lt;vector&gt;
#include &lt;algorithm&gt;


int int_len(int c){
    c = c &gt; 0 ? c : -c;
    int len = 1;
    while (c &gt; 9){
        c /= 10;
        len ++;
    }
    return len;
}


int get_two_last(int &amp; num){
    num = num &gt; 0 ? num : -num; //иначе он будет возвращать не только 2 последние цифры, но и знак
    int c = num%100;
    num /= 100;
    return c;
}


class BigInteger{
public:
    int * arr;
    int sign;
    int len;

    void change_sign(){
        sign = -sign;
    }

    BigInteger(){
        arr = (int*)calloc(1, sizeof(int));
        arr[0] = 0;
        sign = 1;
        len = 1;
    }

    BigInteger(int num){
        arr = (int*)calloc(1, sizeof(int));
        len = int_len(num);
        sign = num &gt;= 0 ? 1 : -1;
        arr = (int*)realloc(arr, (len/2 + 1) * sizeof(int));
        for (int i = len / 2; i &gt;= 0; i--){
            arr[i] = get_two_last(num);
        }
    }
    
    ~BigInteger(){
        free(arr);
    }
};


int get_num_from_BigInteger(BigInteger big_int){
    int len = big_int.len;
    int * arr = big_int.arr;
    int sign = big_int.sign;
    int num = 0;
    for(size_t i = 0; i &lt; len/2 + 1; i++){
        num *= 100;
        num += arr[i];
    }
    return num * sign;
}


BigInteger pluse(BigInteger &amp;big_int_1, BigInteger &amp;big_int_2){
    BigInteger big_int(get_num_from_BigInteger(big_int_1) + get_num_from_BigInteger(big_int_2));
    return big_int;
}


BigInteger minuse(BigInteger big_i
  • 19 января 2025 г. 20:44
Ответы на вопрос 2
В вашем коде есть несколько проблем, которые могут влиять на эффективное управление памятью и функционирование вашего класса `BigInteger`. Позвольте мне предложить несколько улучшений и объяснить, как можно оптимизировать код.

### Основные проблемы и рекомендации:

1. **Управление памятью**:
   - Использование `calloc` и `realloc` в конструкторе может привести к утечкам памяти. Вместо этого лучше использовать стандартный контейнер `std::vector`, который управляет своей памятью автоматически.
   - Также, если вам нужно передавать `BigInteger` как аргумент функции, используйте ссылки или перемещения, чтобы избежать ненужного копирования.

2. **Конструкторы копирования и оператор присваивания**:
   - Реализуйте конструктор копирования и оператор присваивания (оператор копирующего присваивания) для корректного управления ресурсами. Это особенно важно, если вы используете сырые указатели.

3. **Оператор перемещения**:
   - Для повышения производительности реализуйте оператор перемещения.

4. **Оптимизация методов**:
   - Подумайте о том, чтобы сделать некоторые функции `const`, если они не изменяют состояние объекта. Это может помочь с пониманием кода и безопасностью.

5. **Используйте `new` и `delete` вместо `malloc` и `free`**:
   - Поскольку вы используете C++, используйте память с помощью `new` и `delete`, чтобы корректно вызывать конструкторы и деструкторы.

### Возможный улучшенный код:

Вот как может выглядеть улучшенный вариант вашего класса:

```cpp
#include <iostream>
#include <vector>
#include <algorithm>

int int_len(int c) {
    if (c == 0) return 1; // Для нуля
    c = c > 0 ? c : -c;
    int len = 0;
    while (c > 0) {
        c /= 10;
        len++;
    }
    return len;
}

class BigInteger {
public:
    std::vector<int> arr;
    int sign;

    BigInteger() : sign(1) { 
        arr.push_back(0); // Начальное значение 0
    }

    BigInteger(int num) {
        sign = (num >= 0) ? 1 : -1;
        num = std::abs(num);
        int len = int_len(num);
        arr.resize(len / 2 + 1);
        for (int i = len / 2; i >= 0; --i) {
            arr[i] = num % 100;
            num /= 100;
        }
    }

    // Конструктор копирования
    BigInteger(const BigInteger& other) : arr(other.arr), sign(other.sign) {}

    // Оператор присваивания
    BigInteger& operator=(const BigInteger& other) {
        if (this != &other) {
            arr = other.arr;
            sign = other.sign;
        }
        return *this;
    }

    // Оператор перемещения
    BigInteger(BigInteger&& other) noexcept : arr(std::move(other.arr)), sign(other.sign) {
        other.sign = 1; // Сбрасываем знак, чтобы избежать потенциальных проблем
    }

    ~BigInteger() = default; // Память управляется вектором

    // Прочие методы...
};

int main() {
    BigInteger num1(12345);
    BigInteger num2(num1); // Тест копирования
    BigInteger num3 = std::move(num1); // Тест перемещения
    return 0;
}
```

### Объяснение изменений:

- Использование `std::vector` вместо массива, что дает автоматическое управление памятью.
- Поддержка операций копирования и перемещения для корректной работы с объектами класса, что поможет избежать утечек памяти.
- Одновременно повышается читаемость и безопасность кода, избавляя от необходимости использования ручного управления памятью.

Изучите элементы, касающиеся декларации и реализации стандартных методов класса, чтобы обеспечить надлежащее управление ресурсами для ваших объектов.
Проблема вот в этой строчке: 
int get_num_from_BigInteger(BigInteger big_int){

Тут у вас идет передача по значению. У вас создается новая BigInteger переменная, со значением переданной. Поскольку вы конструктор копирования нигде не определили, компилятор сделал его вам сам, и там он тупо копирует все данные класса, включая указатель arr.
В итоге у вас получается два экземпляра класса, в каждом из которых указатель на один и тот же массив. Потом каждый из двух экземпляров в деструкторе вызовет free для одного и того же указатенля, вот и получается двойной free и креш.

Вам надо руководствоватся правилом трех(пяти) . Доопределите конструктор копирования. Вообще, вам бы стоило его запретить ( = delete; ), ибо копировать такие большие числа - это плохо. А в функции ваши передавайте BigInteger по константной ссылке.

Ну и в других функциях та же самая поблема.

И еще, в C++ не стоит использовать malloc/free, используйте new/delete. А еще лучше, используйте std::vector.
Похожие вопросы