Оператор удаления, приведенный ниже, является избыточным кодом.
int *a = new int[100]
if (!doSomething1(a))
delete[] a
return
if (!doSomething2(a))
delete[] a
return
if (!doSomething3(a))
delete[] a
return
return
Одна альтернатива, которую я придумала:
if(doSomething1(a) || doSomething2(a) || doSomething3(a))
;
delete[] a;
return;
Но это не подходит в ситуации, когда я хочу добавить инструкции, указанные для doSomething1 (), например,
if(!doSomething1(a))
foo;
delete[] a;
return;
if(!doSomething2(a))
delete[] a;
return;
Мне сказали, что есть по крайней мере 5 способов уменьшить этот вид избыточности кода. Так какие-нибудь предложения?
обновить, еще один вопрос:
тот же вопрос, давайте ограничим область только C, отметим изменение логики процесса.
char *a = (char*)malloc(100*sizeof(char));
if(doSomething1(a))
foo;
free(a)
return;
if(doSomething2(a))
free(a)
return;
if(doSomething3(a))
free(a);
return;
free(a);
return
Зачем вам нужно что-либо вручную удалять? Это C ++, поэтому мы можем использовать деструкторы и RAII.
std::vector<a>(100);
if (!doSomething1(a))
return;
if (!doSomething2(a))
return;
if (!doSomething3(a))
return;
В более общем плане: если что-то должно произойти, когда вы покидаете область действия, то делайте это в деструкторе автоматического объекта в этой области действия.
Но почему вы используете возвращаемые значения для обозначения сбоя? Это C ++, поэтому мы можем использовать исключения:
std::vector<a>(100);
doSomething1(a);
doSomething2(a);
doSomething3(a);
«RAII» и «выход из области» были бы хорошими поисковыми терминами для Google или SO. Например, посмотрите на Boost.ScopeExit или альтернативы этому. Идея состоит в том, что вы создаете локальный объект и оставляете его деструктор сделать очистку или «наконец» код.
Вот попытка применить идиому непосредственно к вашему примеру, сведенную к минимуму (без проверки ошибок и тому подобного):
class AutomaticDeleter
{
public:
AutomaticDeleter(int *a) : a(a) {}
~AutomaticDeleter() { delete[] a; }
int *GetWrappedPointer() const { return a; }
private:
int *a;
};
// ...
AutomaticDeleter automatic_deleter(new int[100]);
if (!doSomething1(automatic_deleter.GetWrappedPointer()))
return;
if (!doSomething2(automatic_deleter.GetWrappedPointer()))
return;
if (!doSomething3(automatic_deleter.GetWrappedPointer()))
return;
И, конечно, я должен отметить, что это всего лишь пример того, что вы Можно делай не то что ты должен делать при применении идиомы к указателю, особенно тот, который возвращается из new[]
, В реальной жизни вы бы использовали std::vector<int>
и покончим с этим. Идиома имеет гораздо более интересные и полезные приложения.
bool failure;
int *a = new int[100]
if ( failure = !doSomething1(a))
//...
if ( !failure && ( failure = !doSomething2(a) ) )
//...
if ( !failure && ( failure =!doSomething3(a) ) )
//...
if ( failure )
{
delete []a;
return;
}
//,,,
return
do {
if (doSomething1(a) && doSomething2(a) && doSomething3(a)){
break; /*all good: move outside the dummy loop*/
}
/*one of the functions failed*/
delete[] a;
return;
} while (false);
это один из способов. Я полагаюсь на то, что if
оценивает утверждения строго слева направо и останавливает оценку один раз в false
достигнуто
(Эта идиома довольно часто используется в C; см. Исходный код ядра Unix).