Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/delphi/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Delphi 如何测试使用Move复制类型是否安全_Delphi - Fatal编程技术网

Delphi 如何测试使用Move复制类型是否安全

Delphi 如何测试使用Move复制类型是否安全,delphi,Delphi,我正在编写一个通用向量类型: type TBigVector<T: record> = class private FSize: Integer; FEntries: TArray<T>; function GetEntry(Index: Integer): T; procedure SetEntry(Index: Integer; const Value: T); procedure SetSize(Value: In

我正在编写一个通用向量类型:

type
  TBigVector<T: record> = class
  private
    FSize: Integer;
    FEntries: TArray<T>;
    function GetEntry(Index: Integer): T; 
    procedure SetEntry(Index: Integer; const Value: T); 
    procedure SetSize(Value: Integer); 
  public
    constructor Create(ASize: Integer);
    property Size: Integer read FSize write SetSize;
    property Entry[Index: Integer]: T read GetEntry write SetEntry; default;
    procedure Zeroise;
    function ToArray: TArray<T>; 
  end;

现在,对于像
Double
和我定制的
Complex
类型这样的类型,我可以这样做。我知道它们是不受管理的,而且原始内存拷贝不会造成任何困难。我想做的是添加一个运行时检查,可能只在调试版本中调用,它强制执行
T
没有托管类型的约束。我该怎么做呢?

我会这样做:

TDoubleBigVector = class(TBigVector<Double>)
  ....
end;
TComplexBigVector = class(TBigVector<Complex>)
  ....
end;
program SO21753006;

{$APPTYPE CONSOLE}

uses
  TypInfo,
  Windows,
  SysUtils;

type
  TProblemRecord1 = record
    I : Integer;
    S : String;
  end;

  TProblemRecord2 = record
    Obj : TObject;
  end;

  TGoodRecord = record
    I : Integer;
    K : Double;
    S : Array[0..10] of Char;
  end;


  TBigVector<T: record> = class
  private
    FSize: Integer;
    FEntries: TArray<T>;
    function GetEntry(Index: Integer): T;
    procedure SetEntry(Index: Integer; const Value: T);
    procedure SetSize(Value: Integer);
  public
    constructor Create(ASize: Integer);
    property Size: Integer read FSize write SetSize;
    property Entry[Index: Integer]: T read GetEntry write SetEntry; default;
    procedure Zeroise;
    function ToArray: TArray<T>;
  end;


function RecordHasNoManagedTypes(Typ : PTypeInfo) : Boolean;

var
 TypeData : PTypeData;

begin
 Assert(Assigned(Typ));
 Result := True;
 // only check if we have a record, or else we have a value type
 if Typ.Kind = tkRecord then
  begin
   TypeData := GetTypeData(Typ);
   Result := TypeData.ManagedFldCount = 0;
  end;
end;

{ TBigVector<T> }

constructor TBigVector<T>.Create(ASize: Integer);
begin
 Size := ASize;
end;

function TBigVector<T>.GetEntry(Index: Integer): T;
begin
end;

procedure TBigVector<T>.SetEntry(Index: Integer; const Value: T);
begin
end;

procedure TBigVector<T>.SetSize(Value: Integer);
begin
 SetLength(FEntries, Value);
end;

function TBigVector<T>.ToArray: TArray<T>;
begin
end;

procedure TBigVector<T>.Zeroise;
begin
 Assert(RecordHasNoManagedTypes(TypeInfo(T)), 'T must not have managed types!');
 ZeroMemory(Pointer(FEntries), Size*SizeOf(T));
end;

var
  Rec1 : TBigVector<Double>;
  Rec2 : TBigVector<TGoodRecord>;
  Rec3 : TBigVector<TProblemRecord1>;
  Rec4 : TBigVector<TProblemRecord2>;

begin
  try
    Writeln('Double type');
    Rec1 := TBigVector<Double>.Create(1);
    Rec1.Zeroise;
    Writeln('GoodRecord type');
    Rec2 := TBigVector<TGoodRecord>.Create(10);
    Rec2.Zeroise;
    try
     Writeln('Problemrecord1 type');
     Rec3 := TBigVector<TProblemRecord1>.Create(10);
     Rec3.Zeroise;
    except
     on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
    end;
    try
     Writeln('Problemrecord2 type');
     Rec4 := TBigVector<TProblemRecord2>.Create(10);
     Rec4.Zeroise;
    except
     on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
    end;
  except
   on E: Exception do
    Writeln(E.ClassName, ': ', E.Message);
  end;
  Readln;
end.
procedure TBigVector<T>.Zeroise;
begin
 Assert(not RTTI.IsManaged(TypeInfo(T)), 'T must not have managed types!');
 ZeroMemory(Pointer(FEntries), Size*SizeOf(T));
end;
更新2
从XE7开始,您可以使用固有函数
System.IsManagedType(T)
。这将在编译时解决,导致零运行时开销

如果是IsManagedType(T),则断言(false,“T不是托管类型”)


不要执行断言(而不是(IsManagedType(t)),因为编译器将无法删除断言,但如果它不适用,它将删除

@whosrdaddy是的。但我更愿意使用类型信息方法,以与Delphi的RTL相同的方式。我通常在构建时关闭新样式的RTTI。我很高兴看到这两种风格的答案。什么满足了我个人的需要s是一回事,但我怀疑不同风格的答案可能对其他人有价值。类类型是非托管的,没有特殊的编译器支持。
Initialize
Finalize
对它们没有操作,复制它们只会复制原始位。动态数组是托管的。您看到的行为对它们来说很有意义我。+1谢谢。您的回答让我找到了
Rtti.IsManaged
。这可能是一个值得信赖的好服务。问得好,回答得好。有人知道为什么
System.Rtti.IsManaged
不在
系统中。TypInfo
?此函数没有使用任何Rtti内容…托管类型不包括
TObjects
,至少对于非arc平台是这样。另请参见。@whosrdaddy
TObject
对于非arc平台是不受管理的。因此使用
ManagedFldCount
非常适合这个问题。我想也许你应该编辑答案以反映这一点。然后我会接受。
procedure TBigVector<T>.Zeroise;
begin
 Assert(not RTTI.IsManaged(TypeInfo(T)), 'T must not have managed types!');
 ZeroMemory(Pointer(FEntries), Size*SizeOf(T));
end;