考虑这段代码片段
struct Foo {
dummy: [u8; 65536],
}
fn bar(foo: Foo) {
println!("{:p}", &foo)
}
fn main() {
let o = Foo { dummy: [42u8; 65536] };
println!("{:p}", &o);
bar(o);
}
程序的典型结果如下:
0x7fffc1239890
0x7fffc1229890
地址不同。
显然,大数组dummy
已经被复制,正如编译器的移动实现所预期的那样。不幸的是,这可能会对性能产生非常重要的影响,因为dummy
是一个非常大的数组。这种影响可能会迫使人们选择通过引用传递参数,即使函数在概念上实际上“消耗”了该参数。
由于Foo
没有派生Copy
,因此对象o
被移动了。由于Rust禁止访问已移动的对象,是什么阻止了bar
“重用”原始对象o
,从而迫使编译器生成潜在昂贵的按位复制?这是否存在根本的难题,或者我们是否会看到编译器有一天优化掉这种按位复制?
:p
输出并改用test :: black_box,然后从汇编中消除了复制操作。 - Manishearthbar
正在被内联。LLVM在移除大数组的移动操作方面表现不佳。 - VeedracNRVO
标签的问题与此相关:https://github.com/rust-lang/rust/labels/A-mir-opt-nrvo - WiSaGaNo
的释放是否有保证?考虑到它被移出到了bar()
中,o
内存会在什么时候释放? - Ilya Loskutov