快一点;我是否正确认为将字符串传递给方法'作为CONST'涉及比将字符串作为'VAR'传递更多的开销?如果字符串参数声明为CONST,编译器会让Delphi复制字符串然后传递副本吗?
问题的原因有点乏味;我们有一个传统的 Delphi 5 实用程序,其日期确实有编号(替换正在开发中)。它执行大量的字符串处理,经常在各种函数和过程之间传递1-2Kb字符串。在整个代码中,已经遵守了使用CONST或VAR传递参数(取决于手头的工作)的“正确”观察。我们只是在寻找一些“快速获胜”,可能会缩短执行时间几微秒,让我们度过难关,直到新版本准备就绪。我们想过将内存管理器从默认的Delphi 5更改为FastMM,我们也想知道是否值得改变字符串传递的方式 - 因为代码工作正常,字符串传递为const,我们不如果我们将这些声明更改为var,则会发现问题 - 该方法中的代码不会更改字符串。
但实际上它真的会有什么不同吗? (该程序实际上只对这些1kb + ish字符串进行了大量处理;在高峰时间每分钟有数百个字符串)。在重写时,这些字符串被保存在对象/类变量中,因此它们实际上并没有以相同的方式被复制/传递,但在遗留代码中,它非常“老派”帕斯卡。
当然,我们会分析程序的整体运行情况,看看我们已经做了哪些不同但是如果我们在第一次实例中字符串传递的工作原理完全错误的话,实际尝试这一点毫无意义!
答案 0 :(得分:12)
不,在您的案例中使用const
或var
之间不应有任何性能差异。在这两种情况下,都会将指向字符串的指针作为参数传递。如果参数为const
,则编译器只是不允许对其进行任何修改。请注意,如果您遇到棘手问题,这并不排除对字符串的修改:
procedure TForm1.Button1Click(Sender: TObject);
var
s: string;
begin
s := 'foo bar baz';
UniqueString(s);
SetConstCaption(s);
Caption := s;
end;
procedure TForm1.SetConstCaption(const AValue: string);
var
P: PChar;
begin
P := PChar(AValue);
P[3] := '?';
Caption := AValue;
end;
这实际上会改变调用方法中的本地字符串变量,证明只传递指向它的指针。
但绝对使用FastMM4,它应该会产生更大的性能影响。
答案 1 :(得分:9)
const
实质上意味着“我不会改变它,我也不在乎这是通过值还是通过引用传递 - 无论哪个是最有效率的我很好“。粗体部分很重要,因为它实际上是可观察的。请考虑以下代码:
type TFoo =
record
x: integer;
//dummy: array[1..10] of integer;
end;
procedure Foo(var x1: TFoo; const x2: TFoo);
begin
WriteLn(x1.x);
WriteLn(x2.x);
Inc(x1.x);
WriteLn;
WriteLn(x1.x);
WriteLn(x2.x);
end;
var
x: TFoo;
begin
Foo(x, x);
ReadLn;
end.
这里的技巧是我们将var
和const
都传递给同一个变量,这样我们的函数就可以通过一个参数进行变异,看看这是否会影响另一个变量。如果您使用上面的代码进行尝试,则会看到x1.x
内的Foo
递增不会更改x2.x
,因此x2
按值传递。但是尝试取消注释TFoo
中的数组声明,以便它的大小变大,并再次运行它 - 你会看到x2.x
现在如何别名x1.x
,所以我们有传递现在引用x2
!
总而言之,const
始终是传递任何类型参数的最有效方式,但您不应对是否拥有调用者传递的值的副本做出任何假设,或者对某些人的引用(可能由您可能调用的其他代码发生变异)的位置。
答案 2 :(得分:4)
这真是一个评论,但是很长一段时间,请耐心等待。
关于'所谓的'字符串传递值
Delphi 始终通过引用传递string
和ansistring
(不包括WideStrings和ShortStrings)作为指针。
所以字符串永远不会通过值传递
这可以通过传递100MB字符串轻松测试。
只要你没有在被调用的例程字符串体内更改它们,就需要花费O(1)时间(并且在那里有一个小常量)
但是,当传递没有var
或const
子句的字符串时,Delphi会做三件事。
pass by value
。关于通过引用传递(指针)
当字符串作为const
或var
传递时,Delphi也会传递引用(指针),但是:
答案 3 :(得分:3)
使用 const afaik时,编译器不会复制该字符串。使用 const 可以节省为您使用的字符串递增/递减refcounter的开销。
通过将memorymanager升级到FastMM,您将获得更大的性能提升,并且,因为您对字符串做了很多工作,请考虑使用FastCode库。
答案 4 :(得分:2)
Const
已经是将参数传递给函数的最有效方法。它避免了创建副本(默认值,按值)或甚至传递指针(var,通过引用)
对于字符串尤其如此,当计算能力有限且不被浪费时(因此称为“旧学校”标签),确实是要走的路。
IMO,const
应该是默认约定,由程序员根据值或var真正需要时更改它。这可能更符合Pascal的整体安全性(如限制自己在脚下射击的机会)。
我的2¢......