假设我们在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运算的结果使用“ reference ”时会发生什么:
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 ++中的对应运算符效率更高,因为复制行为浅而深?
答案 0 :(得分:3)
通常,将数据保存在堆栈上会更快。商业级C ++编译器通常使用"return value optimization"。
但是在你开始真正衡量表现之前,你永远不会知道哪个更快。涉及的因素太多了。
答案 1 :(得分:2)
是的,F#(作为C#和VB.NET)通过引用传递对象(类实例)(因此没有创建副本),如果你使用结构(在C#中,不确定你是否可以在F#中创建这样的东西)然后它们按值传递(因此创建了副本)。请注意,在C ++中,您也可以双向完成。但是,是的,你提出你的例子的方式,F#解决方案会更有效率。
唉,有人可能会指出,如果你让Matrix成为一个可变对象,那么你将会更加高效(因为不需要创建新的Matrix对象),但是你失去了所有不变性的优点。 / p>
答案 2 :(得分:2)
.NET具有引用和值类型,并且在堆栈上分配值类型(除非它们是引用类型的一部分,但是不要让它们被带走)。在C#中,您将分别使用class
和struct
关键字声明它们。
虽然这不是F#类型声明语义的一部分,但您可以通过使用[<Struct>]
属性告诉编译器将特定类型创建为值类型。