1

假设我们在 F# 中有一个 Matrix 类,并且您重载了 (+) 运算符。然后,我们将有这样的事情:

type Matrix(n : int, m : int) = 
    ...
    static member (+) (A : Matrix, B : Matrix) = 
        let res = new Matrix(A.Dim1, A.Dim2) // suppose A and B have the same dimension
        ... // compute here the sum
        res

与 C/C++ 相比,我们会有这样的东西:

static const Matrix operator+(const Matrix& A, const Matrix& B)
{
    Matrix res(A.Dim1(), A.Dim2());
    ... // compute here the sum
    return res;
}

现在,请注意,在 F# 中,矩阵res是在堆内存中分配的,而 C++ 版本是res堆栈内存中分配的。

到目前为止,一切都很好。观察当我们想要在两个版本中对 sum 运算的结果进行“引用”时会发生什么:

Matrix result = A + B; // deep copy in C++ (because res has to be destroyed after its return)

let result = A + B // shallow copy in F# (res was allocated in the heap memory)

我是否在这里遗漏了某些东西,或者由于浅拷贝和深拷贝行为,F# 中的 (+) 运算符最终比 C/C++ 中的对应运算符更有效?

4

3 回答 3

3

Usually, it is faster to keep data on the stack. And commercial-grade C++ compilers will often use the "return value optimization".

But until you start to actually measure the performance, you will never know which is faster. There are too many factors involved.

于 2010-09-10T07:43:24.830 回答
2

.NET 具有引用类型和值类型,并且值类型是在堆栈上分配的(除非它们是引用类型的一部分,但我们不要忘乎所以)。在 C# 中,您将分别使用classstruct关键字声明它们。

虽然这实际上不是 F# 类型声明语义的一部分,但您可以通过使用[<Struct>]属性告诉编译器将特定类型创建为值类型。

于 2010-09-10T10:45:41.870 回答
2

是的,F#(作为 C# 和 VB.NET)通过引用传递对象(类实例)(所以没有创建副本),如果你使用结构(在 C# 中,不确定你是否可以在 F# 中创建这样的东西)然后它们被传递按价值(因此创建副本)。请注意,在 C++ 中,您也可以采用两种方式。但是,是的,按照您提出示例的方式,F# 解决方案将更加高效。

唉,有人可能会指出,如果你让 Matrix 成为一个可变对象,那么你的性能会更高(因为不需要创建新的 Matrix 对象),但是你会失去不变性的所有优点。

于 2010-09-10T04:15:13.227 回答