5

按照通常的短路评估问题,短路评估是否适用于针对 nil 对象构建和发送的参数?例子:

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

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

4

2 回答 2

9

消息总是被分派给一个对象指针,不管它是指向一个对象还是指向nil. 此外,消息是在运行时发送的,因此编译器不能仅仅假设它nil_array确实存在nil并对其进行优化。如果初始化做了其他事情,nil_array结果是一个实例怎么办?

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

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

主文件

#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;
}

测试.h

@interface Test : NSObject {}

- (void)test:(int)arg;

@end

测试.m

@implementation Test

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

@end

输出

1
测试参数:1
2
3
测试参数:3
于 2011-02-13T16:43:25.647 回答
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;
}

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

当且仅当已知函数是 pure时,编译器才能安全地优化对它的调用,因为调用它不会对程序的其余部分产生影响。然而,GCC 对此非常保守,并且通常(总是?)仅在函数被标记为纯时才这样做,通过__attribute__((__pure__))函数声明上的装饰。

如果一个函数是纯函数,并且从不取消引用指针并且从不访问其堆栈框架之外的任何内存,则可以__attribute__((__const__))在 GCC 中对其进行标记,从而允许进一步的静态分析和优化。

于 2011-02-13T21:28:04.450 回答