【发布时间】:2009-10-21 13:57:11
【问题描述】:
我知道将字符串参数标记为const 可以产生巨大的性能差异,但是序数类型呢?让他们const 有什么好处吗?
我在处理字符串时一直使用const 参数,但从不用于Integer、Pointer、类实例等。
在使用const 时,我经常需要创建额外的临时变量来替换现在写保护的参数,所以我想知道:将序数参数标记为const 有什么好处吗?
【问题讨论】:
标签: delphi
我知道将字符串参数标记为const 可以产生巨大的性能差异,但是序数类型呢?让他们const 有什么好处吗?
我在处理字符串时一直使用const 参数,但从不用于Integer、Pointer、类实例等。
在使用const 时,我经常需要创建额外的临时变量来替换现在写保护的参数,所以我想知道:将序数参数标记为const 有什么好处吗?
【问题讨论】:
标签: delphi
您需要了解原因,以避免“货物崇拜编程”。将字符串标记为 const 会产生性能差异,因为您不再需要在字符串上使用互锁的递增和递减引用计数,随着时间的推移,这种操作实际上会变得更昂贵,而不是更少,因为更多的核心意味着必须做更多的工作来保持原子操作的同步。这是安全的,因为编译器强制执行“此变量不会被更改”约束。
对于通常为 4 字节或更小的序数,没有性能提升。仅当您使用大于 4 个字节的值类型(例如数组或记录)或引用计数类型(例如字符串和接口)时,才使用 const 作为优化。
不过,还有另一个重要优势:代码可读性。如果您将某些内容作为 const 传递并且它对编译器没有任何影响,它仍然可以对 you 产生影响,因为您可以阅读代码并了解其意图最重要的是不要修改它。如果您之前没有看过代码(其他人编写的),或者您在很长一段时间后重新使用它并且不记得您最初编写它时的确切想法,那么这可能很重要。
【讨论】:
Const 禁止函数的序言和尾声中更新字符串引用计数的代码。接口参数和动态数组也是如此。同样,记录作为指针传递。 Const 仅抑制将记录复制到函数的本地堆栈的序言代码。换句话说,const 在函数的 调用者 端没有效果。它只影响呼叫的接收者。
const 与字符串一起使用不会阻止复制!!使用const 只能防止增加引用计数以及隐式try..finally 块。 try..finally 有点贵,但远没有副本那么贵。
您不能不小心将它们视为var 参数并编译您的代码。这样你的意图就很清楚了。
【讨论】:
声明序数类型 const 没有任何区别,因为它们无论如何都会被复制(按值调用),因此对变量的任何更改都不会影响原始变量。
procedure Foo (Val : Integer)
begin
Val := 2;
end;
...
SomeVar := 3;
Foo (SomeVar);
Assert (SomeVar = 3);
恕我直言,声明序数类型 const 没有任何意义,正如您所说,需要您经常引入局部变量。
【讨论】:
这取决于您的日常活动有多复杂以及如何使用它。如果它在很多地方使用并且要求值保持不变,请将其声明为“const”以使其清晰且安全。对于字符串类型,如果声明为“const”,则存在一个错误(对于 Delphi 7,因为我对此感到困惑)会导致内存损坏。下面是示例代码
type
TFoo = class
private
FStr: string;
public
procedure DoFoo(const AStr: string);
begin
FStr := AStr; //the trouble code 1
......
end;
procedure DoFoo2;
begin
.....
DoFoo(FStr); //the trouble code 2
end;
end;
【讨论】:
使用带字符串的 Const 可以显着提高速度:
function test(k: string): string;
begin
Result := k;
end;
function test2(Const k: string): string;
begin
Result := k;
end;
function test3(Var k: string): string;
begin
Result := k;
end;
procedure TForm1.Button1Click(Sender: TObject);
Var a: Integer;
s,b: string;
x: Int64;
begin
s := 'jkdfjklf lkjj3i2ej39ijkl jkl2eje23 io3je32 e832 eu283 89389e3jio3 j938j 839 d983j9';
PerfTimerInit;
for a := 1 to 10000000 do
b := test(s);
x := PerfTimerStopMS;
Memo1.Lines.Add('default: '+x.ToString);
PerfTimerInit;
for a := 1 to 10000000 do
b := test2(s);
x := PerfTimerStopMS;
Memo1.Lines.Add('const: '+x.ToString);
PerfTimerInit;
for a := 1 to 10000000 do
b := test3(s);
x := PerfTimerStopMS;
Memo1.Lines.Add('var: '+x.ToString);
end;
默认值:443 常量:320 变量:325
默认值:444 常量:303 变量:310
默认值:444 常量:302 变量:305
整数也一样:
默认值:142 常量:13 变量:14
有趣的是,在 64 位中,字符串似乎几乎没有区别(默认模式只比 Const 慢一点):
默认值:352 常量:313 变量:314
【讨论】: