Как можно улучшить код класса, представляющего числа в виде массива из двухзначных чисел, а также оптимизировать его функции? Вот мой текущий код: <pre><code class="cpp">#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_i
В вашем коде есть несколько проблем, которые могут влиять на эффективное управление памятью и функционирование вашего класса `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` вместо массива, что дает автоматическое управление памятью.
- Поддержка операций копирования и перемещения для корректной работы с объектами класса, что поможет избежать утечек памяти.
- Одновременно повышается читаемость и безопасность кода, избавляя от необходимости использования ручного управления памятью.
Изучите элементы, касающиеся декларации и реализации стандартных методов класса, чтобы обеспечить надлежащее управление ресурсами для ваших объектов.
Проблема вот в этой строчке: <br/> <code class="cpp">int get_num_from_BigInteger(BigInteger big_int){</code> <br/> <br/> Тут у вас идет передача по значению. У вас создается новая BigInteger переменная, со значением переданной. Поскольку вы конструктор копирования нигде не определили, компилятор сделал его вам сам, и там он тупо копирует все данные класса, включая указатель arr. <br/> В итоге у вас получается два экземпляра класса, в каждом из которых указатель на один и тот же массив. Потом каждый из двух экземпляров в деструкторе вызовет free для одного и того же указатенля, вот и получается двойной free и креш. <br/> <br/> Вам надо руководствоватся <a href="https://ru.wikipedia.org/wiki/%D0%9F%D1%80%D0%B0%D0%B2%D0%B8%D0%BB%D0%BE_%D1%82%D1%80%D1%91%D1%85_(C%2B%2B)" rel="nofollow">правилом трех(пяти)</a> . Доопределите конструктор копирования. Вообще, вам бы стоило его запретить ( <code class="cpp">= delete;</code> ), ибо копировать такие большие числа - это плохо. А в функции ваши передавайте BigInteger по константной ссылке. <br/> <br/> Ну и в других функциях та же самая поблема. <br/> <br/> И еще, в C++ не стоит использовать malloc/free, используйте new/delete. А еще лучше, используйте std::vector.