Objective-C 是否对 nil 对象的消息使用短路求值?
按照通常的短路评估问题,进行短路评估适用于针对 nil 对象构建和发送的参数吗?示例:
NSMutableArray *nil_array = nil;
....
[nil_array addObject:[NSString stringWithFormat:@"Something big %@",
function_that_takes_a_lot_of_time_to_compute()]];
该慢速函数是否会被调用,或者整个 addObject 调用是否会在不处理参数的情况下被优化?
Following the usual short-circuit evaluation question, does short-circuit evaluation work for parameters built and sent against nil objects? Example:
NSMutableArray *nil_array = nil;
....
[nil_array addObject:[NSString stringWithFormat:@"Something big %@",
function_that_takes_a_lot_of_time_to_compute()]];
Is that slow function going to be called or will the whole addObject call be optimized out without processing the parameters?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
消息总是被分派到对象指针,无论它是指向对象还是指向
nil
。此外,消息是在运行时发送的,因此编译器不能仅仅假设 nil_array 确实是 nil 并将其优化掉。如果初始化做了其他事情,并且 nil_array 结果是一个实例怎么办?这意味着您作为参数传递给方法的所有表达式都将被评估以便传递,因此不会发生任何类型的短路。你的慢函数将会被执行,如果需要很长时间就会影响你的程序的性能。
编辑:我只是为它编写了一个小测试用例(空的 Objective-C 命令行程序)。如果您运行此命令并观察调试器控制台,您会注意到对
function_that_takes_a_lot_of_time_to_compute()
的所有三个调用的输出都会出现(以 5 秒为间隔),而仅来自t1
的输出code> 和t3
的test:
方法自然会出现,因为它们不是nil
。main.m
Test.h
Test.m
输出
A message is always dispatched to an object pointer, regardless of whether it points to an object or points to
nil
. Additionally, messages are sent in the runtime and therefore the compiler cannot just assumenil_array
really isnil
and optimize it away. What if the initialization did something else, andnil_array
turns out to be an instance?That means all the expressions you pass as arguments to your methods will be evaluated in order to be passed, so no short-circuiting of any sort happens. Your slow function will be executed, and if it takes a long time it'll affect the performance of your program.
EDIT: I just whipped up a little test case for the heck of it (empty Objective-C command line program). If you run this and observe the debugger console, you'll notice that output from all three calls to
function_that_takes_a_lot_of_time_to_compute()
appears (in 5-second intervals), while output from onlyt1
's andt3
'stest:
methods appears — naturally, since these are notnil
.main.m
Test.h
Test.m
Output
接受的答案是一个很好的答案,但我想补充一点:
function_that_takes_a_lot_of_time_to_compute()
或+[NSString stringWithFormat:]
可能会产生副作用,所以即使我们知道 100 %确定nil_array
为nil
(我们有时可以通过静态分析知道这一点),程序仍然必须执行function_that_takes_a_lot_of_time_to_compute ()
和+[NSString stringWithFormat:]
以确保其行为符合预期。如果函数
f()
没有副作用,则它被认为是“纯粹的”。这意味着它可以接受输入参数并可以返回一个值,但它从不调用任何非纯函数,也从不修改程序或全局内存的任何部分(传递参数和返回值涉及的内存在这里不计算在内。 ) 例如,以下函数是“纯”函数:C 标准库中的纯函数示例为
memcmp()
和strlen()
。当且仅当已知函数是纯函数时,编译器才可以安全地优化对其的调用,因为不调用它不会对程序的其余部分产生影响。然而,GCC 在这方面非常保守,通常(总是?)仅当函数被标记为纯函数时,通过 __attribute__((__pure__)) 修饰才这样做。函数声明。
如果一个函数是纯函数,并且从不取消引用指针,也从不访问其堆栈帧之外的任何内存,则可以在 GCC 中将其标记为 __attribute__((__const__)),这允许进一步的静态分析和优化。
The accepted answer is a good one, but I wanted to add:
function_that_takes_a_lot_of_time_to_compute()
or+[NSString stringWithFormat:]
can have side effects, so even if we knew with 100% certainty thatnil_array
wasnil
(and we can sometimes know this through static analysis), the program would still have to executefunction_that_takes_a_lot_of_time_to_compute()
and+[NSString stringWithFormat:]
to ensure it was behaving as expected.If a function
f()
has no side effects, it is considered "pure." This means that it can take input arguments and can return a value, but it never calls any non-pure functions and never modifies any part of the program or global memory (the memory involved in passing arguments and return values doesn't count here.) The following function, for instance, is "pure":Examples of pure functions within the C standard library are
memcmp()
andstrlen()
.If and only if a function is known to be pure, the compiler could safely optimize away calls to it, since not calling it would have no effect on the rest of the program. However, GCC is very conservative about doing this, and generally (always?) does it only when a function is marked pure, via the
__attribute__((__pure__))
decoration on the function declaration.If a function is pure, and in addition never dereferences pointers and never accesses any memory outside its stack frame, it can instead be marked
__attribute__((__const__))
in GCC, which allows even further static analysis and optimization.