函数应该返回一个自身引用还是一个自身的新副本?

huangapple go评论72阅读模式
英文:

Should my function return a self reference or a new copy of self?

问题

在上面的源代码中,from_column_vectors() 方法返回一个新对象的拷贝。另一方面,from_row_vectors() 方法返回对 self 的引用。

在性能关键的应用中,应该选择使用 from_column_vectors()

原因是在 from_column_vectors() 方法中,新的 Matrix3x3 对象是通过从 self._array 复制数据而创建的,而不是返回对现有对象的引用。这样,在每次调用 from_column_vectors() 方法时,都会创建一个新的对象,不会影响原始对象的状态。相比之下,在 from_row_vectors() 方法中,它返回对现有对象的引用,这意味着在性能关键的情况下,如果在返回的引用上进行修改,可能会影响到其他部分使用同一对象的代码,从而引入潜在的错误和不稳定性。

因此,为了避免在性能关键应用中引入潜在的错误和不稳定性,推荐使用 from_column_vectors() 方法,因为它提供了更可控和可预测的行为。

英文:
use Vec3::Vec3;

struct Matrix3x3
{
    _array: [f64; 9],
}

impl Matrix3x3
{
    pub fn new(m: [f64; 9]) -> Self
    {
        Matrix3x3 { _array: m}
    }

    pub fn from_column_vectors(&self, cx: &Vec3, cy: &Vec3, cz: &Vec3) -> Matrix3x3
    {
        let cx1 = cx.normalized();
        let cy1 = cy.normalized();
        let cz1 = cz.normalized();

        self._array[0] = cx1.x;
        self._array[1] = cx1.y;
        self._array[2] = cx1.z;

        self._array[3] = cy1.x;
        self._array[4] = cy1.y;
        self._array[5] = cy1.z;

        self._array[6] = cz1.x;
        self._array[7] = cz1.y;
        self._array[8] = cz1.z;

        return Matrix3x3::new(self._array);
    }

    pub fn from_row_vectors(&self, rx: &Vec3, ry: &Vec3, rz: &Vec3) -> &Matrix3x3
    {
        let cx1 = rx.normalized();
        let cy1 = ry.normalized();
        let cz1 = rz.normalized();

        self._array[0] = cx1.x;
        self._array[1] = cy1.x;
        self._array[2] = cz1.x;

        self._array[3] = cx1.y;
        self._array[4] = cy1.y;
        self._array[5] = cz1.y;

        self._array[6] = cx1.z;
        self._array[7] = cy1.z;
        self._array[8] = cz1.z;

        return self;
    }
}

In the above source code, from_column_vectors() returns a copy of self as a new object. On the other hand, from_row_vectors() returns a reference to the self.

Which option should I practice in the case of performance-critical applications?

Explain why.

答案1

得分: 2

这两个函数都应该返回一个新值,因为它们都不对*self中已有的内容做任何操作。实际上,这些函数应该根本就不应该有self参数,因为它们明显被命名为构造函数。

如果有人想要覆盖现有的Matrix3x3,他们可以简单地将这些函数调用的结果赋值给它。如果你担心性能问题,注意到返回值优化(RVO)应该会避免拷贝,你可以通过启用优化编译并检查生成的汇编代码来进行测试。

例如:

struct Matrix3x3
{
    _array: [f64; 9],
}

impl Matrix3x3
{
    pub fn new(m: [f64; 9]) -> Self
    {
        Matrix3x3 { _array: m }
    }

    pub fn from_column_vectors(cx: &Vec3, cy: &Vec3, cz: &Vec3) -> Self
    {
        let cx1 = cx.normalized();
        let cy1 = cy.normalized();
        let cz1 = cz.normalized();
        
        Self::new([
            cx1.x, cx1.y, cx1.z,
            cy1.x, cy1.y, cy1.z,
            cz1.x, cz1.y, cz1.z,
        ])
    }

    pub fn from_row_vectors(rx: &Vec3, ry: &Vec3, rz: &Vec3) -> Self
    {
        let rx1 = rx.normalized();
        let ry1 = ry.normalized();
        let rz1 = rz.normalized();
        
        Self::new([
            rx1.x, ry1.x, rz1.x,
            rx1.y, ry1.y, rz1.y,
            rx1.z, ry1.z, rz1.z,
        ])
    }
}

然后,如果有人想要覆盖现有的值,他们可以这样做:

let mut x: Matrix3x3 = todo!();
x = Matrix3x3::from_column_vectors(todo!(), todo!(), todo!());
英文:

Both of these should return a new value because neither do anything with whatever was already in *self. In fact, there shouldn't even be any self parameter to begin with, as these are clearly named to be constructor functions.

If one wants to clobber an existing Matrix3x3 then they can just assign from the result of calling one of these functions. If you are concerned about performance, not that RVO should elide the copy, and this is something you can test by compiling with optimizations and inspecting the generated assembly.

For example:

struct Matrix3x3
{
    _array: [f64; 9],
}

impl Matrix3x3
{
    pub fn new(m: [f64; 9]) -> Self
    {
        Matrix3x3 { _array: m }
    }

    pub fn from_column_vectors(cx: &Vec3, cy: &Vec3, cz: &Vec3) -> Self
    {
        let cx1 = cx.normalized();
        let cy1 = cy.normalized();
        let cz1 = cz.normalized();
        
        Self::new([
            cx1.x, cx1.y, cx1.z,
            cy1.x, cy1.y, cy1.z,
            cz1.x, cz1.y, cz1.z,
        ])
    }

    pub fn from_row_vectors(rx: &Vec3, ry: &Vec3, rz: &Vec3) -> Self
    {
        let rx1 = rx.normalized();
        let ry1 = ry.normalized();
        let rz1 = rz.normalized();
        
        Self::new([
            rx1.x, ry1.x, rz1.x,
            rx1.y, ry1.y, rz1.y,
            rx1.z, ry1.z, rz1.z,
        ])
    }
}

Then, if someone wants to overwrite an existing value, they can:

let mut x: Matrix3x3 = todo!();
x = Matrix3x3::from_column_vectors(todo!(), todo!(), todo!());

huangapple
  • 本文由 发表于 2023年3月7日 17:11:56
  • 转载请务必保留本文链接:https://go.coder-hub.com/75659959.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定