Что лучший способ к свободной памяти после возврата из ошибки?

Видите, вы здесь не правы

@Override
    public int getCount() {
        return 0;
    }

Сделайте это

 @Override
    public int getCount() {
        return songs.size();
    }

Также удалите эти два метода:

 @Override
    public Object getItem(int position) {
        return null;
    }

    @Override
    public long getItemId(int position) {

    return 0;
}

Объяснение [1110 ] Адаптер использует метод getCount (), чтобы определить размер списка, и просмотр повторного просмотра, который вы возвращаете 0, означает, что у вас есть 0 элементов в просмотре списка. На самом деле нам нужно вернуть общий размер элементов, который составляет songs.size().

Надеюсь, что это даст вам правильное руководство.

12
задан Andrew Keeton 20 February 2009 в 16:54
поделиться

9 ответов

Я знаю, что люди, ненавидят для использования их, но это - идеальная ситуация для a goto в C.

int func( void** mem1, void** mem2 )
{
    int retval = 0;
    *mem1 = malloc(SIZE);
    if (!*mem1) {
        retval = 1;
        goto err;
    }

    *mem2 = malloc(SIZE);
    if (!*mem2) {
        retval = 1;
        goto err;
    }
// ...     
    goto out;
// ...
err:
    if( *mem1 ) free( *mem1 );
    if( *mem2 ) free( *mem2 );
out:
    return retval;
}      
25
ответ дан 2 December 2019 в 03:49
поделиться

Это немного спорно, но я думаю goto подход, используемый в ядре Linux на самом деле, работает вполне прилично в этой ситуации:

int get_item(item_t* item)
{
  void *mem1, *mem2;
  int ret=-ENOMEM;
  /* allocate memory */
  mem1=malloc(...);
  if(mem1==NULL) goto mem1_failed;

  mem2=malloc(...);
  if(mem2==NULL) goto mem2_failed;

  /* take a lock */
  if(!mutex_lock_interruptible(...)) { /* failed */
    ret=-EINTR;
    goto lock_failed;
  }

  /* now, do the useful work */
  do_stuff_to_acquire_item(item);
  ret=0;

  /* cleanup */
  mutex_unlock(...);

lock_failed:
  free(mem2);

mem2_failed:
  free(mem1);

mem1_failed:
  return ret;
}
4
ответ дан 2 December 2019 в 03:49
поделиться

Это - то, где goto является соответствующим, по-моему. Я раньше следовал за anti-goto догмой, но я изменил это, когда было указано мне, что делают {...} В то время как (0); компиляции к тому же коду, но не так легко читать. Просто следуйте некоторым основным правилам, как не движение назад с ними, сведение к минимуму их, только использование их для состояний ошибки, и т.д...

int func(void **mem1, void **mem2)
{
    *mem1 = NULL;
    *mem2 = NULL;

    *mem1 = malloc(SIZE);
    if(!*mem1)
        goto err;

    *mem2 = malloc(SIZE);
    if(!*mem2)
        goto err;

    return 0;
err:
    if(*mem1)
        free(*mem1);
    if(*mem2)
        free(*mem2);

    *mem1 = *mem2 = NULL;

    return 1;
}
7
ответ дан 2 December 2019 в 03:49
поделиться

Вызывающая сторона делает что-либо полезное с блоками памяти, которые были правильно выделены перед отказом? В противном случае вызываемый должен обработать освобождение.

Одна возможность сделать очистку эффективно использует do..while(0), который позволяет break где Ваш пример returns:

int func(void **mem1, void **mem2)
{
    *mem1 = NULL;
    *mem2 = NULL;

    do
    {
        *mem1 = malloc(SIZE);
        if(!*mem1) break;

        *mem2 = malloc(SIZE);
        if(!*mem2) break;

        return 0;
    } while(0);

    // free is NULL-safe
    free(*mem1);
    free(*mem2);

    return 1;
}

Если Вы делаете много выделений, Вы могли бы хотеть использовать Ваш freeAll() функция, чтобы сделать очистку здесь также.

1
ответ дан 2 December 2019 в 03:49
поделиться

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

void *mem1 = NULL;
void *mem2 = NULL;

if (func(&mem1, &mem2)) {
    freeAll(2, mem1, mem2);
    return 1;
}
0
ответ дан 2 December 2019 в 03:49
поделиться

Лично; У меня есть библиотека отслеживания ресурсов (в основном сбалансированное двоичное дерево), и у меня есть оболочки для всех функций распределения.

Ресурсы (такие как память, сокеты, дескрипторы файлов, семафоры и т. Д. - все, что вы выделяете и освобождаете), может принадлежать set.

У меня также есть библиотека обработки ошибок, в которой первым аргументом каждой функции является набор ошибок, и если что-то пойдет не так, функция, в которой возникла ошибка, отправляет ошибку в набор ошибок.

Если установлена ​​ошибка содержит ошибку, ни одна функция не выполняется . (У меня есть макрос в верхней части каждой функции, которая вызывает ее возврат.)

Итак, несколько маллоков выглядят так:

mem[0] = malloc_wrapper( error_set, resource_set, 100 );
mem[1] = malloc_wrapper( error_set, resource_set, 50 );
mem[2] = malloc_wrapper( error_set, resource_set, 20 );

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

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

res_delete_set( resource_set );

Мне не нужно специально проверять ошибки - в моем коде нет if (), проверяющих возвращаемые значения, что делает его поддерживаемым; Я считаю, что расширение встроенной проверки ошибок ухудшает удобочитаемость и, следовательно, ремонтопригодность. У меня просто хороший простой список вызовов функций.

Это art , человек: -)

res_delete_set( resource_set );

Мне не нужно специально проверять ошибки - в моем коде нет if (), проверяющих возвращаемые значения, что делает его поддерживаемым; Я считаю, что расширение встроенной проверки ошибок ухудшает удобочитаемость и, следовательно, ремонтопригодность. У меня просто хороший простой список вызовов функций.

Это art , человек: -)

res_delete_set( resource_set );

Мне не нужно специально проверять ошибки - в моем коде нет if (), проверяющих возвращаемые значения, что делает его поддерживаемым; Я считаю, что расширение встроенной проверки ошибок ухудшает удобочитаемость и, следовательно, ремонтопригодность. У меня просто хороший простой список вызовов функций.

Это art , человек: -)

2
ответ дан 2 December 2019 в 03:49
поделиться

Это удобочитаемая альтернатива:

int func(void **mem1, void **mem2) {
  *mem1 = malloc(SIZE);
  *mem2 = malloc(SIZE);
  if (!*mem1 || !*mem2) {
    free(*mem2);
    free(*mem1);
    return 1;
  }
  return 0;
}
2
ответ дан 2 December 2019 в 03:49
поделиться

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

int func(void **mem1, void **mem2)
{
    *mem1 = malloc(SIZE);
    if (!*mem1) return 1;

    *mem2 = malloc(SIZE);
    if (!*mem2) {
        /* Insert free statement here */
        free(*mem1);
        return 1;
    }

    return 0;
}

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

0
ответ дан 2 December 2019 в 03:49
поделиться

Я немного напуган всеми рекомендациями по выражению goto!

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

Быть тем, кто любит рефакторинг вещей, чтобы минимизировать мою возможность забыть вещи (например, очистка указателя), я бы сначала добавил несколько функций. Я предполагаю, что вполне вероятно, что я буду многократно использовать их в одной программе. Функция imalloc () будет выполнять операцию malloc с косвенным указателем; ifree () отменит это. cifree () освободит память условно.

Имея это под рукой, моя версия кода (с третьим аргументом, для демонстрации) будет такой:

// indirect pointer malloc
int imalloc(void **mem, size_t size)
{
   return (*mem = malloc(size));
}

// indirect pointer free
void ifree(void **mem)
{
   if(*mem)
   {
     free(*mem);
     *mem = NULL;
   }
}

// conditional indirect pointer free
void cifree(int cond, void **mem)
{
  if(!cond)
  {
    ifree(mem);
  }
}

int func(void **mem1, void **mem2, void **mem3)
{
   int result = FALSE;
   *mem1 = NULL;
   *mem2 = NULL;
   *mem3 = NULL;

   if(imalloc(mem1, SIZE))
   {
     if(imalloc(mem2, SIZE))
     {
       if(imalloc(mem3, SIZE))
       {
         result = TRUE;
       }            
       cifree(result, mem2);
     }
     cifree(result, mem1);
   }
  return result;
}

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

-2
ответ дан 2 December 2019 в 03:49
поделиться
Другие вопросы по тегам:

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