17

GUI 应用程序中的这段代码编译并运行:

procedure TForm1.Button1Click(Sender: TObject);
begin
  Self := TForm1.Create(Owner);
end;

(用 Delphi 6 和 2009 测试)

  • 为什么自写而不是只读?
  • 这在哪些情况下有用?

编辑:

  • 这在德尔福棱镜中也可能吗?(我想是的,看这里

更新:使用自我分配的德尔福应用程序/库:

4

5 回答 5

11

这并不像它可能的那么糟糕。我刚刚在 Delphi 2009 中对其进行了测试,看起来,虽然 Self 参数不使用const语义,你似乎暗示它应该使用它,但它也没有使用var语义,所以你可以全部改变它希望在您的方法中,而不会实际丢失调用者对您的对象持有的引用。那将是一件非常糟糕的事情。

至于原因,二选一。要么是一个简单的疏忽,要么是 Marco 建议的:允许您将 Self 传递给var参数。

于 2009-05-02T12:24:01.937 回答
7

也许允许传递给 const 或 var 参数?

这可能是人工制品,因为系统在 := 符号左侧的任何地方都没有 self 。

于 2009-05-02T11:40:21.247 回答
5

分配给自我是如此不合逻辑和无用,以至于这个“功能”可能是一个疏忽。与可赋值常量一样,纠正这些问题并不总是那么容易。

这里的简单建议是:不要这样做。

于 2009-05-02T17:16:29.473 回答
2

实际上,“Self”只是对堆栈中某个位置的名称引用,该位置存储指向堆中对象的地址。对这个变量强制只读是可能的,显然设计者决定不这样做。我认为这个决定是武断的。

看不到任何有用的情况,这只会更改堆栈中的值。此外,更改此值可能很危险,因为无法保证引用实例成员的代码的行为将在编译器版本之间保持一致。

更新:回应PatrickvL评论

“变量”“Self”不在堆栈上(据我所知,从来没有);相反,它的值在调用任何对象方法之前被放入寄存器(准确地说是 EAX)。——</p>

不,Self 在内存中有实际地址。试试这个代码,看看你自己。

procedure TForm1.Button1Click(Sender: TObject);
begin
  ShowMessage(IntToStr(Integer(@Self)));
end;

procedure TForm1.Button2Click(Sender: TObject);
var
  newform: TForm;
  p: ^Integer;
begin
  Self.Caption := 'TheOriginal';
  newform := TForm.Create(nil);
  try
    newform.Caption := 'TheNewOne';
    // The following two lines is, technically, the same as
    //   Self := newform;
    p := Pointer(@Self);
    p^ := Integer(newform);
    ShowMessage(Self.Caption);  // This will show 'TheNewOne' instead of 'TheOriginal'
  finally
    Self.Free; // Relax, this will free TheNewOne rather than TheOriginal
  end;
end;
于 2009-05-02T12:04:21.690 回答
1

有时,当您想尽可能地优化方法时(不诉诸汇编),“Self”可以(ab)用作“自由”变量 - 它可能只是意味着使用堆栈和使用堆栈之间的区别使用寄存器。

当然,堆栈的内容很可能已经存在于 CPU 缓存中,因此访问速度应该很快,但寄存器更快。

作为旁注:我仍然怀念在 Amiga 的摩托罗拉 68000 上编程并拥有 16 个数据和 16 个地址寄存器的日子……我不敢相信世界选择了有限的 4 个寄存器80x86 系列处理器!

最后一点,我有时会选择使用 Self,因为 Delphi 的优化器实际上并没有优化得那么好。(至少,与可以在各种 LLVM 优化器中找到的诡计相比,它相形见绌。)恕我直言,当然还有 YMMV。

于 2010-03-30T11:49:33.093 回答