Objective-C是否对消息使用短路评估为零对象?

Grz*_*icz 5 objective-c short-circuiting

按照通常的短路评估问题,对零个对象建立和发送的参数进行短路评估工作吗?例:

NSMutableArray *nil_array = nil;
....
[nil_array addObject:[NSString stringWithFormat:@"Something big %@",
     function_that_takes_a_lot_of_time_to_compute()]];
Run Code Online (Sandbox Code Playgroud)

是否会调用慢速函数,还是在不处理参数的情况下优化整个addObject调用?

Bol*_*ock 9

始终将消息分派给对象指针,无论它指向对象还是指向nil.此外,消息在运行时发出,因此编译器不能想当然地认为nil_array真的是nil和优化它拿走.如果初始化做了别的事情,nil_array结果是一个实例怎么办?

这意味着您将作为参数传递给方法的所有表达式都将被评估以便传递,因此不会发生任何类型的短路.您的慢速函数将被执行,如果它需要很长时间,它将影响您的程序的性能.

编辑:我刚刚为它做了一个小测试用例(空的Objective-C命令行程序).如果你运行它并观察调试器控制台,你会注意到所有三个调用的输出都会function_that_takes_a_lot_of_time_to_compute()出现(以5秒为间隔),而只有t1's和t3' test:方法的输出出现 - 当然,因为它们不是nil.

的main.m

#import "Test.h"

int function_that_takes_a_lot_of_time_to_compute(void)
{
    static int i = 1;

    sleep(5);
    NSLog(@"%d", i);

    return i++;
}

int main(int argc, const char *argv[])
{
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

    Test *t1 = [[Test alloc] init], *t2 = nil, *t3 = [[Test alloc] init];

    [t1 test:function_that_takes_a_lot_of_time_to_compute()];
    [t2 test:function_that_takes_a_lot_of_time_to_compute()]; // nil
    [t3 test:function_that_takes_a_lot_of_time_to_compute()];

    [t1 release];
    [t3 release];

    [pool drain];
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

Test.h

@interface Test : NSObject {}

- (void)test:(int)arg;

@end
Run Code Online (Sandbox Code Playgroud)

Test.m

@implementation Test

- (void)test:(int)arg
{
    NSLog(@"Testing arg: %d", arg);
}

@end
Run Code Online (Sandbox Code Playgroud)

产量

1
Testing arg: 1
2
3
Testing arg: 3


Jon*_*pan 6

接受的答案很好,但我想补充一下:

function_that_takes_a_lot_of_time_to_compute()+[NSString stringWithFormat:]有副作用,所以即使我们知道100%的把握认为nil_arraynil(我们可以知道,有时候这种通过静态分析),该计划将仍然必须执行function_that_takes_a_lot_of_time_to_compute(),并+[NSString stringWithFormat:] 确保它被表现如预期.

如果一个函数f()没有副作用,它被认为是"纯粹的".这意味着,它可以利用输入参数并返回一个值,但它永远不会调用任何非纯函数,从不修改程序或全局存储器(参与传递参数的内存的任何部分和返回值这里不计.例如,以下函数是"纯粹的":

int munge(float foo, char bar) {
    unsigned short quux = bar << 4;
    return foo + quux;
}
Run Code Online (Sandbox Code Playgroud)

C标准库中的纯函数示例是memcmp()strlen().

当且仅当一个函数被认为是纯函数时,编译器可以安全地优化对它的调用,因为调用它将对程序的其余部分没有影响.然而,GCC对这样做是非常保守的,并且通常(总是?)仅在函数被标记为纯时通过__attribute__((__pure__))函数声明上的装饰来做.

如果一个函数是纯函数,另外从不取消引用指针并且永远不会访问其堆栈帧之外的任何内存,它可以改为__attribute__((__const__))在GCC中标记,这允许进一步的静态分析和优化.