在我用它们执行操作之前,有些地方检查有效指针;这些检查有时可以很深入地嵌套。
例如,我有
if (a)
{
if (a->b())
{
if (a->b()->c())
{
a->b()->c()->DoSomething();
}
}
}
我真的不喜欢这个样子。有没有办法把它变成更具可读性的东西?理想情况下,
if (a && a->b() && a->b()->c() )
{
...
}
会很棒,但显然不行。
编辑 - nvm我提出的例子正如大家所指出的那样工作。我测试了它是否有效,但我的测试中的代码中有一个错误。杜!
答案 0 :(得分:28)
为什么后者不起作用?
在C,&&是一个短路操作符,因此从左到右进行评估,如果任何评估为假,则评估停止。
事实上,你可以写:
a && a->b() && a->b()->c() && a->b()->c()->DoSomething();
答案 1 :(得分:13)
引自K&R 1 :
由
&&
或||
连接的表达式从左到右进行评估,并保证只要知道真相或谎言,评估就会停止。
因此后一个例子将完美地运作,如WhirlWind has noted。
1 The C Programming Language,第二版,第21页。
答案 2 :(得分:5)
您的第二个示例适用于C / C ++。当第一个FALSE值被击中时,它会短路。
答案 3 :(得分:4)
你从其他答案中看到使用&&将起作用,并在遇到空指针时将评估短路。
我心烦意乱的程序员喜欢避免重复方法调用这样的测试,因为如果它们是幂等的,它会避免担心。一种选择是像这样重写
A* a;
B* b;
C* c;
if ((a=a()) && (b=a->b()) && (c=b->c())) {
c->doSomething();
}
不可思议的是冗长而且有点笨重,但至少你知道每个方法只被调用一次。
答案 4 :(得分:3)
为什么'显然不起作用'?由于&&
运算符仅在左侧有效时才评估正确的术语,因此重写非常安全。
答案 5 :(得分:3)
既然你已经收到了问题的直接答案,我只会提到你所拥有的长链电话有代码味道,你可能会考虑更好的设计。在这种情况下,这样的设计可能包括使用空对象模式,以便您的调用可以归结为:
a->CDoSomething();
答案 6 :(得分:3)
链接有效,但它不一定是最好的一般情况答案,特别是因为它模糊了失败点。我建议通过反转逻辑来使测试变平,以便在失败时退出。
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来表示它们的失败,那么所有这些都是不必要的。如果需要静默失败,那么空对象模式将是合适的。
答案 7 :(得分:2)
if (a && a->b() && a->b()->c()) { a->b()->c()->DoSomething(); }
C ++执行延迟评估,因此这将起作用。首先,a将被评估,如果它为0,则整个条件为假,因此不会对其他部分进行评估。
这也适用于||
运算符。如果你写if (a || b)
,如果a为真,则不会评估b。
答案 8 :(得分:0)
如果您只想拨打DoSomething()
,那么第二个就可以使用。