我有类似下面的代码
let x = Arc::new(Mutex::new(Thing::new()));
work_on_data(x.clone());
do_more_work_on_data(x.clone());
x
没有在第二个函数之后使用,因此不需要第二个克隆。我应该手动删除 clone()
还是对其进行优化?
最佳答案
为什么不呢?
优化编译器的首要原则是假设规则,它指定只要编译器可以证明优化是不可观察的,就可以优化任何东西。
注意:这是在某些允许特定优化的语言之上的。
例如:
#[derive(Clone, Debug)]
struct MyDummyType(u64);
extern {
fn print_c(_: *const ());
}
#[inline(never)]
fn print(dummy: MyDummyType) {
unsafe { print_c(&dummy as *const _ as *const _) }
}
fn main() {
let x = MyDummyType(42);
print(x.clone());
print(x.clone());
}
产生以下 main
:
; Function Attrs: nounwind uwtable
define internal void @_ZN8rust_out4main17h0c6f2596c7f28a79E() unnamed_addr #1 {
entry-block:
tail call fastcc void @_ZN8rust_out5print17h1f2d1a86beea10d7E(i64 42)
tail call fastcc void @_ZN8rust_out5print17h1f2d1a86beea10d7E(i64 42)
ret void
}
编译器完全看穿了我们的代码(实际上我不得不使用一个外部函数来强制它在 main
中发出一些代码)。
那么,你的情况呢?
老实说,这要困难得多。
具体来说,由于 Drop
,语义可能会发生变化:
- 使用
do_more_work_on_data(x.clone())
,x
保证在执行结束后 被删除,因此任何一方 -Drop
的效果在当前函数的末尾执行, - 对于
do_more_work_on_data(x)
,x
可能 在do_more_work_on_data
的末尾被丢弃,或者它可能是较早地掉落在某处。
所以为了证明优化不可观察,编译器必须证明:
- 要么
Drop
没有效果, - 或者
Drop
将在do_more_work_on_data
的最后执行,这与紧随其后的相同, - 或者……?
这有多大可能?
Mutex
的Drop
实现需要调用 FFI,因此从优化器的角度来看,它具有可观察到的效果。
所以这一切都取决于 do_more_work_on_data
是否被内联。如果是这样,确实可以优化多余的 clone
。如果没有,我不会屏住呼吸。
关于memory - 克隆语句是否被优化过?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42669949/