Задать вопрос
@TyGGer4ik

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

У меня есть класс, в котором я представляю число как массив 2х значных чисел (цифр числа), идущих в соответственном порядке. Вот сам код:
#include <iostream>
#include <cstdlib>
#include <vector>
#include <algorithm>


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


int get_two_last(int & num){
    num = num > 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 >= 0 ? 1 : -1;
        arr = (int*)realloc(arr, (len/2 + 1) * sizeof(int));
        for (int i = len / 2; i >= 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 < len/2 + 1; i++){
        num *= 100;
        num += arr[i];
    }
    return num * sign;
}


BigInteger pluse(BigInteger &big_int_1, BigInteger &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_int_1, BigInteger big_int_2){
    big_int_2.change_sign();
    return pluse(big_int_1, big_int_2);
}


int main(){
    //BigInteger my_int(-454);
    //std::cout << get_num_from_BigInteger(my_int);
    return 0;
}


//Что на это мне говорит сам компилятор:
// SIGABRT
//free(): double free detected in tcache 2
Фактически проблема заключается в том, что на этапе вызова деструктора он почему-то не видит переменную моего массива (проверенно в дебагере), хотя если убрать всё лишнее и оставить только массив, то всё компилируется и работает исправно:
#include <cstdlib>
#include <iostream>


class My_Class{
public:
    int * arr;
    My_Class(){
        arr = (int *)calloc(sizeof(int));
    }
    My_Class(int n){
        arr = (int *)calloc(sizeof(int) * n);
    }
    ~My_Class(){
        free(arr);
    }
};


int main(){
    int a;
    std::cin >> a;
    My_Class my_class(a);
    for (size_t i = 0; i < a; i++){
        std::cout << my_class.arr[i] << ", ";
    }
    std::cout <<std::endl;
    return 0;
}


У меня есть подозрение, что что-то не так происходит на моменте с реаллоцированием памяти в исходном варианте
  • Вопрос задан
  • 13 просмотров
Подписаться 1 Простой Комментировать
Пригласить эксперта
Ответы на вопрос 1
wataru
@wataru Куратор тега C++
Разработчик на С++, экс-олимпиадник.
Проблема вот в этой строчке:
int get_num_from_BigInteger(BigInteger big_int){

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

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

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

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

Войдите, чтобы написать ответ

Похожие вопросы