Delphi XE t字节的正确用法
TBytes变量的正确使用模式是什么?根据我的理解,TBytes不是一个类,而是一个“动态字节数组”。我不确定在哪里为它分配内存,何时释放内存,以及哪种方式是将内存从生产者传递给消费者的最佳方式。我希望生产者创建一个TBytes实例,然后将其传递给消费者。发生这种情况后,生产者希望重用其TBytes成员变量,即消费者最终将内存返回给系统的内容。如果TBytes是一个对象,我不会有任何问题,但我不确定TBytes在这个场景中是如何工作的 例如,在对象A中,我想将一些数据组合到作为对象A成员的TBytes数组中。完成后,我想将TBytes数组传递给另一个对象B,该对象B随后成为数据的所有者。同时,回到对象A,我想开始组装更多数据,重用TBytes成员变量Delphi XE t字节的正确用法,delphi,delphi-xe,Delphi,Delphi Xe,TBytes变量的正确使用模式是什么?根据我的理解,TBytes不是一个类,而是一个“动态字节数组”。我不确定在哪里为它分配内存,何时释放内存,以及哪种方式是将内存从生产者传递给消费者的最佳方式。我希望生产者创建一个TBytes实例,然后将其传递给消费者。发生这种情况后,生产者希望重用其TBytes成员变量,即消费者最终将内存返回给系统的内容。如果TBytes是一个对象,我不会有任何问题,但我不确定TBytes在这个场景中是如何工作的 例如,在对象A中,我想将一些数据组合到作为对象A成员的TBy
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;
提前谢谢 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(p^, Pointer(FData)^, n);
if n>0 then
Move(p^, FData[0], n);
我个人并不觉得演员阵容太糟糕,因为无论怎样,Move
绝对没有类型安全性
现在重用FData合法吗?也许是通过复制新的(不同的)数据 我觉得没有更多的背景,我无法回答这个问题。例如,我不知道为什么
FData
是一个字段,因为它只在本地用于该函数。作为一个局部变量,它更有意义。它被声明为字段可能是有原因的,但从这段代码中很难看出它
您需要了解如何使用生产者/消费者模式。通常,这样做是为了使生产与消费脱钩。然而,您的示例代码并没有做到这一点,可能是因为解耦的代码过于复杂,无法包含在这里 对于真正的生产者/消费者实现,您需要将数据的所有权从生产者转移到消费者。根据我们上面所描述的,一种非常简单有效的方法是使用引用计数。当数据传输到消费者时,生产者应释放对其的引用。Move(p^,FData,n);这没关系 过程TClassB.ProcessData(d:t字节);//d是FData的引用计数 开始 //d不保存任何内容,但FData保持不变,refcount=1 //如果您将“var”关键字放在d前面,FData将被释放 设定长度(d,0)
结束 您的代码中有几个误用。以下几点更为正确:
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;
类型
TClassA=类
私有的
FData:TBytes;
公众的
过程汇编输入(p:指针;n:本机输入);
结束;
TClassB=class
公众的
过程数据(变量d:t字节);
结束;
变量
答:塔克拉萨;
b:TClassB;
过程TClassA.AssembleInput(p:Pointer;n:NativeUInt);
开始
设定长度(FData,n);
如果n0,则移动(p^,FData[0],n);
...
b、 ProcessData(FData);
//FData已准备好在此处重复使用。。。
结束;
过程TClassB.ProcessData(变量d:TBytes);
开始
...
设定长度(d,0);
结束;
不,不正常。它将字节从p中的地址移动到FData中的指针。应该是FData[0]。感谢您的解释。是的,FData是成员变量的原因是生产者从TCP套接字获取数据,因此每次调用时通常只获取部分数据。是的,我确实想要生产者/消费者,关于“需要转移数据所有权”的评论正是我想要做的。是的,解耦的代码太复杂了;因此简化了。最后,我仍然不确定如何正确地“转移所有权”——你能澄清一下这个问题吗?让消费者参考一下,然后发布生产者的参考。Consumer.data:=FData;FData:=零;