是否移动了返回值?

时间:2017-11-17 08:09:57

标签: rust

使用此代码:

struct Point {
    x: f64,
    y: f64,
}

struct Rectangle {
    p1: Point,
    p2: Point,
}

impl Rectangle {
    pub fn new(x1: f64, y1: f64, x2: f64, y2: f64) -> Rectangle {
        let r = Rectangle {
            p1: Point { x: x1, y: y1 },
            p2: Point { x: x2, y: y2 },
        };
        // some code where r is used
        r
    }
}

let rectangle = Rectangle::new(0.0, 0.0, 10.0, 10.0);

从内存的角度来看,rectangle是与r相同的实例,还是r的副本?

我是否必须通过引用显式返回(类似&r)?

我必须创造数百万个矩形,我不希望那里有无用的副本。

1 个答案:

答案 0 :(得分:14)

  

从内存的角度来看,rectangle是与r相同的实例,还是r的副本?

<强>未指定的

Rust语言指定了语言的语义,虽然它们在某种程度上限制了实现,但在这种情况下却没有。如何将返回值传递给调用堆栈是 ABI 的一部分,不仅ABI不稳定(在Rust中),它也是特定于平台的。

  

我是否必须通过引用显式返回(类似&r)?

Returning by reference is not possible

您可以返回Box<Rectangle>,但内存分配的成本会使首先复制Rectangle的成本相形见绌,因此这是不可取的。

您可以使用输出参数强制执行此操作,但这还有其他问题:

  • 如果你有&mut Rectangle参数,首先需要有一个有效的实例,必须初始化;相当浪费,
  • 如果您有*mut Rectangle指向未初始化的内存,则需要使用unsafe代码,几乎不满意。

...然而

  

我必须创造数百万个矩形,我不希望那里有无用的副本。

我认为你无所畏惧。

性能调优的第一条规则是先测量;而且我怀疑你是否能够在数百万个矩形的创建中观察到性能问题。

编译器有多个技巧,例如:

  • 甚至没有实现rectangle实例开始,而是通过CPU寄存器传递其组件,
  • 在呼叫网站内联new,避免任何副本,
  • ...

因此,在担心复制4 f64的成本之前,我会实现天真的解决方案,在发布模式下编译,并观察会发生什么。