Как избежать длинной цепочки free's (или удаляет) после каждой проверки на ошибки в C?

Так много сложных методов ... Просто найдите все группы с названием «Названия» и присоединитесь к нижнему варианту с обложкой с подчеркиванием.

>>> import re
>>> def camel_to_snake(string):
...     groups = re.findall('([A-z0-9][a-z]*)', string)
...     return '_'.join([i.lower() for i in groups])
...
>>> camel_to_snake('ABCPingPongByTheWay2KWhereIsOurBorderlands3???')
'a_b_c_ping_pong_by_the_way_2_k_where_is_our_borderlands_3'

Если вы не хотите, чтобы цифры, такие как первый символ группы или отдельная группа - вы можете использовать маску ([A-z][a-z0-9]*).

16
задан bodacydo 27 July 2010 в 00:31
поделиться

6 ответов

Вы можете определить новую метку , которая освободит ресурсы, а затем вы можете ПОЛУЧИТЬ это всякий раз, когда ваш код не работает.

char* function()
{
    char* retval = NULL;
    char* mem = get_memory(100);  // first allocation
    if (!mem)
        goto out_error;

    struct binder* b = get_binder('regular binder');  // second allocation
    if (!b)
        goto out_error_mem;

    struct file* f = mk_file();  // third allocation
    if (!f)
        goto out_error_b;

    /* ... Normal code path ... */
    retval = good_value;

  out_error_b:
    free_binder(b);
  out_error_mem:
    free(mem);
  out_error:
    return retval;
}

Управление ошибками с помощью GOTO уже обсуждалось здесь: Допустимое использование goto для управления ошибками в C?

35
ответ дан 30 November 2019 в 15:35
поделиться

Хотя я восхищаюсь вашим подходом к защитному кодированию, и это хорошо. И каждый программист C должен иметь такой менталитет, он может применяться и к другим языкам ...

Я должен сказать, что это единственная полезная вещь в GOTO, несмотря на то, что пуристы скажут иначе, это было бы эквивалентно окончательному блоку, но есть одна особая ошибка, которую я могу видеть там ...

код karlphillip почти завершен, но .... предположим, что функция была выполнена следующим образом

    char* function() {
      struct file* f = mk_file();  // third allocation
      if (!f) goto release_resources;
      // DO WHATEVER YOU HAVE TO DO.... 
      return some_ptr;
   release_resources:
      free(mem);
      free_binder(b);
      return NULL;
    }

Будьте осторожны !!! Это будет зависеть от дизайна и назначения функции, которую вы считаете нужной, откладывая в сторону ... если бы вы вернулись из этой функции, вы могли бы в конечном итоге провалиться через метку release_resources .... которая могла бы При возникновении незначительной ошибки все ссылки на указатели в куче исчезают и могут привести к возврату мусора ... поэтому убедитесь, что если у вас есть выделенная память и верните ее обратно, используйте ключевое слово return непосредственно перед меткой, в противном случае память может исчезнуть ... или создать утечку памяти ...

5
ответ дан 30 November 2019 в 15:35
поделиться

Если ваши структуры данных являются сложными / вложенными, одного перехода может быть недостаточно, и в этом случае я предлагаю что-то вроде:

mystruct = malloc(sizeof *mystruct);
if (!mystruct) goto fail1;
mystruct->data = malloc(100);
if (!mystruct->data) goto fail2;
foo = malloc(sizeof *foo);
if (!foo) goto fail2;
...
return mystruct;
fail2:
free(mystruct->data);
fail1:
free(mystruct);

Пример из реального мира будет более сложным и может включать несколько уровней Вложение структуры, связанные списки и т. д. Обратите внимание, что здесь нельзя вызвать free(mystruct->data); (поскольку разыменование элемента из mystruct недопустимо), если первый malloc не удался.

2
ответ дан 30 November 2019 в 15:35
поделиться

Вы также можете использовать противоположный подход и проверить на успех:

struct binder* b = get_binder('regular binder');  // second allocation
if(b) {
   struct ... *c = ...
   if(c) {
      ...
   }
   free(b);
}
3
ответ дан 30 November 2019 в 15:35
поделиться

Я знаю, что меня линчуют за это, но у меня был друг, который сказал, что они использовали для этого goto .

Затем он сказал мне, что в большинстве случаев этого недостаточно, и теперь он использовал setjmp () / longjmp () . По сути, он заново изобрел исключения C ++, но с гораздо меньшей элегантностью.

При этом, поскольку goto может работать, вы можете преобразовать его во что-то, что не использует goto , но отступы быстро выйдут из-под контроля:

char* function() {
    char* result = NULL;
    char* mem = get_memory(100);
    if(mem) {
        struct binder* b = get_binder('regular binder');
        if(b) {
            struct file* f = mk_file();
            if (f) {
                // ...
            }
            free(b);
        }
        free(mem);
    }
    return result;
}

Кстати, разброс объявлений локальных переменных по блоку, подобный этому, не является стандартом C.

Теперь, если вы понимаете, что free (NULL); определяется стандартом C как do- ничего, вы можете упростить вложение:

char* function() {
    char* result = NULL;

    char* mem = get_memory(100);
    struct binder* b = get_binder('regular binder');
    struct file* f = mk_file();

    if (mem && b && f) {
        // ...
    }

    free(f);
    free(b);
    free(mem);

    return result;
}
5
ответ дан 30 November 2019 в 15:35
поделиться

Если вы хотите сделать это без goto , вот подход, который хорошо масштабируется:

char *function(char *param)
{
    int status = 0;   // valid is 0, invalid is 1
    char *result = NULL;
    char *mem = NULL:
    struct binder* b = NULL;
    struct file* f = NULL:

    // check function parameter(s) for validity
    if (param == NULL)
    {
        status = 1;
    }

    if (status == 0)
    {
        mem = get_memory(100);  // first allocation

        if (!mem)
        {
            status = 1;
        }
    }

    if (status == 0)
    {
        b = get_binder('regular binder');  // second allocation

        if (!b)
        {
             status = 1;
        }
    }

    if (status == 0)
    {
        f = mk_file();  // third allocation

        if (!f)
        {
             status = 1;
        }
    }

    if (status == 0)
    {
        // do some useful work
        // assign value to result
    }

    // cleanup in reverse order
    free(f);
    free(b);
    free(mem);

    return result;
}
2
ответ дан 30 November 2019 в 15:35
поделиться
Другие вопросы по тегам:

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