Повторное использование указателя двойного массива без утечки памяти в C ++ через «delete» приводит к сбою программы - PullRequest
0 голосов
/ 16 апреля 2019

Я попробовал (несколько сомнительное) соглашение delete после использования, но, похоже, это не работает. Предполагается, что программа получает входные данные одного целого числа, сортирует случайно созданный массив и печатает истекшее время для сортировки, но когда я оставляю там delete, программа ненормально завершает работу даже без предупреждения после ввода , Другими словами, он падает. Однако, когда я закомментирую только строку delete, программа выполняется отлично.

MWE измеряет время для простого алгоритма быстрой сортировки, и, поскольку это школьный проект, я не могу изменить функцию main() и использовать класс QuickSort и его указатели и т. Д.

Единственное, что я могу изменить, - это то, что входит в различные функции, и, хотя кажется, что set(double*, int) может быть просто интегрирован в конструктор, это не является возможным вариантом по какой-то причине.

Цель - определить значение по умолчанию double* в конструкторе, а затем удалить его и скопировать input_array в this->arr в set:

РЕДАКТИРОВАТЬ: я использую Windows 10 и компилятор GCC C ++ из MinGw-w64. Все компиляции были выполнены в командной строке Windows.

main.cpp

#include <iostream>
#include <cstdlib> // Just for good measure, though this shouldn't be needed
#include "Sort.hpp"

bool check_quick(QuickSort *quick_sort) {
    int i = 0;
    while(i < (quick_sort->size) - 1) {
        if (quick_sort->arr[i] > quick_sort->arr[i + 1]) break;
        ++i;
    } if (i == (quick_sort->size) - 1) return true;
    else return false;
}

int main() {
    int n; cin >> n;
    double *input_array = new double[n];
    srand((unsigned int)time(NULL));
    for (int k = 0; k < n; k++) input_array[k] = (double)((rand() % n));

    QuickSort* quick_sort = new QuickSort();
    quick_sort->set(input_array, n);
    quick_sort->run();
    if (check_quick(quick_sort)) {
        cout << "QuickSort is validated" << endl << endl;
    } delete quick_sort;
}

Sort.hpp

#define CLOCKS_PER_SECOND 1000
#include <iostream>
#include <ctime>
#include <iomanip> // Use to call setprecision(4)
using namespace std;

class QuickSort {
    friend bool check_quick(QuickSort*); // Give access for private variables
public:
    void print_time() const {
        cout << "QuickSort : " << fixed << setprecision(4) << seconds
             << " sec" << endl;
        // << fixed << setprecision(4) always prints to four numbers after point
    }
    QuickSort() {
        this->arr = new double[10];
        for (int i = 0; i < 10; ++i) this->arr[i - 1] = i; // Set default array
        seconds = clock(); // Set current Millisecond to starting time
    }
    ~QuickSort() {
        delete this->arr; // Delete array in object of this class
    }
    void sorter(double *arr, int begin, int end) { // Sorting Recursive Function
        // Size of array without pivot is: end - begin
        int pivot = arr[end];
            // PIVOT is element at end of subarray "arr[begin...end]"
        int i = begin, j = end;
        while (i <= j) {
            while (arr[i] < pivot) i++; // Increment until arr[i] is larger than
            while (arr[j] > pivot) j--; // Decrement until arr[j] is lesser than
            if (i <= j) { // If the larger element precedes lesser element
                swap(arr[i], arr[j]); // Call Swap function
                i++; j--;
            } // If i is larger than j now, i was 1 lesser than j before,
              // effectively leaving no more elements to scan.
        }
        if (begin < j) sorter(this->arr, begin, j); // Recursive, larger part
        if (end > i) sorter (this->arr, i, end); // Recursive, lesser part
    }
    void run() {
        sorter(this->arr, 0, this->size - 1); // Call Sorter function
        seconds = (double)(clock() - seconds) / (double)(CLOCKS_PER_SECOND);
            // Calculate Difference of Ticks and divide by Ticks per second.
            // Now, `seconds` is passed seconds with millisecond precision.
    }
    void set(double *arr, int size) {
        this->arr = new double[size]; // Make new array of `size` size
        for (int i = 0; i < size; i++) this->arr[i] = arr[i]; // Copy input_arr
        for (int i = 0; i < size; i++) cout << this->arr[i] << endl; // Copy input_arr
        this->size = size; // Save global `size` to object of class
    }
    void swap(double &p, double &q) { // Swap Function
                                      // Ampersand precedence to change input
        double x = p; // Temporary `double` saver
        p = q; // p is q
        q = x; // q is x, which is p
    }
private:
    double *arr;
    int size;
    double seconds;
};

Ответы [ 3 ]

3 голосов
/ 16 апреля 2019

В вашем конструкторе QuickSort вы пишете за пределами выделенного массива:

this->arr = new double[10];
for (int i = 0; i < 10; ++i) this->arr[i - 1] = i; // Set default array

В первой итерации i равно 0, поэтому this->arr[i - 1] записывает вэлемент -1.Это происходит только при вызове delete, как если бы вы этого не делали, среда выполнения не замечает это повреждение и завершает работу корректно.

Предположительно, простое изменение i-1 на i приведет к желаемому поведению.

2 голосов
/ 16 апреля 2019

Быстрый просмотр показывает, что вы используете delete вместо delete[] ..

этой строки:

delete this-> arr;// Удалить массив в объекте этого класса

должно быть:

delete [] this-> arr;// Удалить массив в объекте этого класса

Кроме того, в соответствии с соглашением удаления вы должны также сделать это:

delete [] this-> arr;
this-> arr = nullptr;// Это важно, иначе вы дважды удаляете, что вызывает неприятности.

2 голосов
/ 16 апреля 2019

Первая строка QuickSort::set:

this->arr = new double[size]; // Make new array of `size` size

утечка массива, выделенного в конструкторе QuickSort. Вам нужно сначала delete[] этот массив, прежде чем присваивать arr указатель на другой:

delete[] arr;
this->arr = new double[size]; // Make new array of `size` size

Если бы это был реальный мир, а не школьное задание, было бы намного лучше не использовать необработанный указатель в этом случае. Скорее, std::vector<double> было бы гораздо более уместным.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...