TBytes变量的正确使用模式是什么?根据我的理解,TBytes不是一个类,而是一个"动态字节数组".我不确定在哪里释放内存,释放它时,哪个是从生产者传递给消费者的最佳方式.我希望我的生产者创建一个TBytes实例,然后将其传递给消费者.在这种情况发生之后,生产者想要重用其TBytes成员变量,知道消费者最终将内存返回给系统的内容.如果TBytes是一个对象,我不会有任何问题,但我不确定TBytes在这种情况下是如何工作的.
例如,在对象A中,我想将一些数据组装成一个TBytes数组,该数组是对象A的成员.完成后,我想将TBytes数组传递给另一个对象B,然后该对象成为该对象的所有者.数据.同时,回到对象A,我想开始组装更多数据,重用TBytes成员变量.
type
  TClassA = class
  private
    FData: TBytes;
  public
    procedure AssembleInput(p: Pointer; n: Cardinal);
  end;
  TClassB = class
  public
    procedure ProcessData(d: TBytes);
  end;
var
  a: TClassA;
  b: TClassB;
procedure TClassA.AssembleInput(p: Pointer; n: Cardinal);
begin
  SetLength(FData, n);
  Move(p^, FData, n);  // Is this correct?
  ...
  b.ProcessData(FData);
  ...
  // Would it be legal to reuse FData now?  Perhaps by copying new (different)
  // data into it?
end;
procedure TClassB.ProcessData(d: TBytes);
begin
  // B used the TBytes here.  How does it free them?
  SetLength(d, 0);  // Does this free any dynamic memory behind the scenes?
end;
提前致谢!
Dav*_*nan 15
Delphi动态数组是具有自动生命周期管理的托管类型.它们被引用计数,当引用计数变为0时,处理.你可以认为它们在字符串,接口和变体方面是等效的.
您可以通过以下三种方式之一显式释放对动态数组的引用:
a := nil;
Finalize(a);
SetLength(a, 0);
但是,在变量离开范围时,通常只是不执行任何操作并释放引用.
使用动态数组时要注意的一件事是,对同一动态数组有两个引用.在这种情况下,通过一个引用应用的更改在另一个引用中是可见的,因为只有一个对象.
SetLength(a, 1);
a[0] := 42;
b := a;
b[0] := 666;//now a[0]=666
你问这是否正确:
Move(p^, FData, n);
不它不是.你在这里做的是将内容复制p到引用上FData.如果你想复制,Move那么你可以写:
Move(p^, Pointer(FData)^, n);
或者如果你想更加冗长并避免演员表演你可以写:
if n>0 then 
  Move(p^, FData[0], n);
我个人对演员来说并不觉得太糟糕,因为Move绝对没有类型安全.
现在重用FData是否合法?也许通过将新的(不同的)数据复制到其中?
没有更多的背景,我觉得我无法回答这个问题.例如,我不知道为什么FData是一个字段,因为它仅在本地用于该函数.作为局部变量会更有意义.据推测,有一个原因它被声明为一个字段,但它不能轻易地从这个代码中辨别出来.
您关于使用生产者/消费者模式.通常这样做是为了将生产与消费分离.但是,您的示例代码不会这样做,可能是因为解耦代码太复杂而无法包含在此处.
对于真正的生产者/消费者实现,您需要将数据的所有权从生产者转移到消费者.根据我们上面所描述的,一种非常简单有效的方法是使用引用计数.当数据传输给消费者时,生产者应该释放对它的引用.
您的代码中有一些误用。下面的说法会更正确:
type
  TClassA = class
  private
    FData: TBytes;
  public
    procedure AssembleInput(p: Pointer; n: NativeUInt);
  end;
  TClassB = class
  public
    procedure ProcessData(var d: TBytes);
  end;
var
  a: TClassA;
  b: TClassB;
procedure TClassA.AssembleInput(p: Pointer; n: NativeUInt);
begin
  SetLength(FData, n);
  if n <> 0 then Move(p^, FData[0], n);
  ...
  b.ProcessData(FData);
  // FData is ready for reuse here...
end;
procedure TClassB.ProcessData(var d: TBytes);
begin
  ...
  SetLength(d, 0);
end;
| 归档时间: | 
 | 
| 查看次数: | 11163 次 | 
| 最近记录: |