Функция очистки в C - PullRequest
       6

Функция очистки в C

1 голос
/ 26 февраля 2020

У меня есть программа C, которая выделяет несколько буферов, которые необходимо очистить, прежде чем программа завершит выполнение. Моя main программа выглядит следующим образом

int main(int argc, char** argv){
    // Some code
    // ...
    // ...
    void* data1 = malloc(someSize);
    void* data2 = malloc(someSize);
    double* result = malloc(resultSize);
    double* buffer = malloc(buffSize);
    // Some code
    // ...
    // First exit point
    if(someExitcondition){
        // free all allocated memory
        exit(1);
    }
    // Some code
    // ...
    // Second exit point
    if(someOtherExitcondition){
        // free all allocated memory
        exit(1);
    }
    // Some code
    // ...

    // free all allocated memory
    return 0;
}

Я хочу упростить очистку, просто вызвав функцию cleanUp(), которая будет free всю память, выделенную в куче. Я хочу вызывать эту функцию непосредственно перед каждым вызовом exit(1) и перед строкой return 0 (по существу, каждый комментарий // free all allocated memory заменяется вызовом cleanUp()). Мой вопрос таков: как передать указатели data1, data2, result и buffer на cleanUp() так, чтобы их можно было освободить?

Это что я думаю сделать. Это правильный подход?

void cleanUp(void* p1, void* p2, void* p3, void* p4){
    // call to free for each pointer
}

Ответы [ 3 ]

3 голосов
/ 26 февраля 2020

Если вас когда-либо учили никогда не использовать goto, что-то вроде этого является ярким примером хорошего времени для использования goto.

int main(int argc, char** argv){
    int ret_status = 0;
    // Some code
    // ...
    // ...
    void* data1 = malloc(someSize);
    void* data2 = malloc(someSize);
    double* result = malloc(resultSize);
    double* buffer = malloc(buffSize);
    // allocation failure: first exit point
    if(!(data1 && data2 && result && buffer)){
        ret_status = 1;
        goto cleanup;
    }
    // Some code
    // ...
    // Second exit point
    if(someOtherExitcondition){
        ret_status = 1;
        goto cleanup;
    }
    // Some code
    // ...

cleanup:
    // free all allocated memory     
    free(data1);
    free(data2);
    free(result);
    free(buffer);

    return ret_status;
}

Если, в отличие от данного примера, Вы также вызывали exit() из вложенных функций, посмотрите на использование atexit(), как указано в ответе Джонатана Леффлера.

2 голосов
/ 26 февраля 2020

Более или менее, но, возможно, лучшим подходом является регистрация обратного вызова с atexit(). Он будет вызываться всякий раз, когда программа завершается нормально (через exit() или при возврате из main() в код запуска). Недостатком является то, что сигнатура функции очистки - void cleanup(void) - без аргументов. Это означает, что функция должна иметь доступ к глобальным (или файловым областям) переменным. Но это дает максимальную надежность для выполнения очистки.

Существует также аргумент, что, если ваша программа собирается завершить работу, не имеет значения, вызываете ли вы free() или нет - система выпустит память в любом случае. Тем не менее, такие программы, как Valgrind будут жаловаться на потерю памяти, если вы не освободите ее - часто это хорошая практика, даже если вы освобождаете ее.

0 голосов
/ 26 февраля 2020

Просто вызовите

    cleanUp(data1, data2, result, buffer);

, поскольку эти переменные имеют в качестве значений назначенные указатели, и это то, что вы в любом случае передали бы free().

Я думаю, что лучше подход заключается в использовании оператора goto в разделе очистки в конце вашей функции. Это один из немногих случаев, когда goto более полезен, чем вреден. Представьте, как бы выглядел ваш код, если бы у вас было 50 функций, использующих этот тип буферов, и у всех них должна быть своя соответствующая функция очистки.

Проверьте ответ Кристиана Гиббонса.

...