Вложенный, Если (x) проверки - Лучший способ записать это?

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

Например, я имею

if (a)
{
  if (a->b())
  {
    if (a->b()->c())
    {
      a->b()->c()->DoSomething();
    } 
  }
}

Мне действительно не нравится вид этого. Существует ли способ превратить это во что-то более читаемое? Идеально,

if (a && a->b() && a->b()->c() )
{
 ...
}

было бы большим, но очевидно не будет работать.

РЕДАКТИРОВАНИЕ - nvm пример, который я поднял, ДЕЙСТВИТЕЛЬНО работает, как все указали. Я действительно проверял его, чтобы видеть, работает ли это, но была ошибка в моем коде в моем тесте. понятное дело!

7
задан Will 20 May 2010 в 17:03
поделиться

9 ответов

Почему последнее не работает?

В C && - это оператор короткого замыкания, поэтому он оценивается слева направо, и если какое-либо из оценок ложно, оценка останавливается.

Фактически, вы могли бы написать:

a && a->b() && a->b()->c() && a->b()->c()->DoSomething();
28
ответ дан 6 December 2019 в 04:46
поделиться

Из других ответов вы видели, что использование && будет работать и приведет к короткому замыканию оценки при обнаружении нулевого указателя.

Непростой программист во мне любит избегать повторения вызовов методов для подобных тестов, поскольку это позволяет не беспокоиться о том, идемпотентны они или нет. Один из вариантов - это переписать так

A* a;
B* b;
C* c;

if ((a=a()) && (b=a->b()) && (c=b->c())) {
  c->doSomething();
}

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

4
ответ дан 6 December 2019 в 04:46
поделиться

Почему «явно не сработает»? Поскольку оператор && оценивает только правый член, если левый действителен, перезапись совершенно безопасна.

3
ответ дан 6 December 2019 в 04:46
поделиться

Поскольку вы уже получили прямой ответ на свой вопрос, я просто упомяну, что длинные цепочки вызовов, как у вас, имеют запах кода, и вы можете подумать о лучшем дизайне. Такой дизайн может в этом случае включать использование шаблона нулевого объекта, чтобы ваш вызов мог просто сводиться к:

a->CDoSomething();
3
ответ дан 6 December 2019 в 04:46
поделиться

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

if (!pa)
  return Fail("No pa");

B* pb = pa->b();
if (!pb)
  return Fail("No pb");

C* pc = b->c();
if (!pc)
  return Fail("No pc");

pc->DoSomething();

То же самое, но плоский и легко читаемый. Кроме того, поскольку он сразу же обрабатывает случай отказа, он не переводится в else, до написания которого вы, возможно, так и не доберетесь.

В этом примере я предположил, что вы не хотите просто молча терпеть неудачу, поэтому я добавил Fail в качестве помощника, который регистрирует текст и возвращает false. Вы также можете просто выбросить исключение. На самом деле, если бы различные методы сигнализировали о своей неудаче, выбрасывая соответствующее исключение, а не возвращая null, то все это было бы ненужным. Если желателен молчаливый отказ, то уместен шаблон объекта null.

3
ответ дан 6 December 2019 в 04:46
поделиться

if (a && a->b() && a->b()->c()) { a->b()->c()->DoSomething(); }

C++ выполняет ленивую оценку, поэтому это будет работать. Сначала будет оценено a, и если оно равно 0, то все условие будет ложным, поэтому остальные части оцениваться не будут.

Это работает и для оператора ||. Если вы напишете if (a || b), то b не будет оценено, если a истинно.

2
ответ дан 6 December 2019 в 04:46
поделиться

Второй будет работать, если вы хотите вызвать только DoSomething () .

0
ответ дан 6 December 2019 в 04:46
поделиться

Ваш второй пример действительно работает на C / C ++. Он замыкается при достижении первого значения FALSE.

5
ответ дан 6 December 2019 в 04:46
поделиться

Цитата из K&R 1 :

Выражения, связанные && или || , вычисляются слева правильно, и гарантируется, что оценка прекратится, как только станет известна правда или ложь.

Следовательно, последний пример будет работать идеально, как отметил WhirlWind .


1 Язык программирования C , второе издание, стр. 21.

13
ответ дан 6 December 2019 в 04:46
поделиться