J'implémente une matrice N x M (classe) avec un enregistrement et un tableau dynamique interne comme ci-dessous.Copie en profondeur d'un enregistrement avec R1: = R2, ou Y at-il un bon moyen d'implémenter la matrice NxM avec enregistrement?
TMat = record
public
// contents
_Elem: array of array of Double;
//
procedure SetSize(Row, Col: Integer);
procedure Add(const M: TMat);
procedure Subtract(const M: TMat);
function Multiply(const M: TMat): TMat;
//..
class operator Add(A, B: TMat): TMat;
class operator Subtract(A, B: TMat): TMat;
//..
class operator Implicit(A: TMat): TMat; // call assign inside proc.
// <--Self Implicit(which isn't be used in D2007, got compilation error in DelphiXE)
procedure Assign(const M: TMat); // copy _Elem inside proc.
// <-- I don't want to use it explicitly.
end;
Je choisis un dossier, parce que je ne veux pas créer/Free/Assigner à l'utiliser. Mais avec un tableau dynamique, les valeurs ne peuvent pas être copiées (en profondeur) avec M1: = M2, au lieu de M1.Assign (M2).
J'ai essayé de déclarer la méthode de conversion auto-implicite, mais elle ne peut pas être utilisée pour M1: = M2.
(Implicite (const pA: PMAT): TMAT et M1: = @ M2 fonctionne, mais il est assez laid et illisible ..)
Est-il possible de brancher la cession de l'enregistrement?
Ou est-il suggéré d'implémenter une matrice N x M avec des enregistrements?
Merci d'avance.
Edit:
Je mis en œuvre comme ci-dessous avec la méthode de Barry et a confirmé qu'il fonctionne correctement.
type
TDDArray = array of array of Double;
TMat = record
private
procedure CopyElementsIfOthersRefer;
public
_Elem: TDDArray;
_FRefCounter: IInterface;
..
end;
procedure TMat.SetSize(const RowSize, ColSize: Integer);
begin
SetLength(_Elem, RowSize, ColSize);
if not Assigned(_FRefCounter) then
_FRefCounter := TInterfacedObject.Create;
end;
procedure TMat.Assign(const Source: TMat);
var
I: Integer;
SrcElem: TDDArray;
begin
SrcElem := Source._Elem; // Allows self assign
SetLength(Self._Elem, 0, 0);
SetLength(Self._Elem, Length(SrcElem));
for I := 0 to Length(SrcElem) - 1 do
begin
SetLength(Self._Elem[I], Length(SrcElem[I]));
Self._Elem[I] := Copy(SrcElem[I]);
end;
end;
procedure TMat.CopyElementsIfOthersRefer;
begin
if (_FRefCounter as TInterfacedObject).RefCount > 1 then
begin
Self.Assign(Self); // Self Copy
end;
end;
Je suis d'accord que ce n'est pas efficace. Utiliser simplement Assign avec un enregistrement pur est absolument plus rapide.
Mais il est très pratique et plus facile à lire. (Et intéressant. :-)
Je pense qu'il est utile pour le calcul de lumière ou le prototypage de pré-production. N'est-ce pas?
Edit2:
kibab donne la fonction d'obtenir le nombre de référence de tableau dynamique lui-même.
La solution de Barry est plus indépendante de l'impl interne, et fonctionne peut-être sur les compilateurs 64bit à venir sans aucune modification, mais dans ce cas, je préfère l'efficacité de kibab pour sa simplicité &. Merci.
TMat = record
private
procedure CopyElementsIfOthersRefer;
public
_Elem: TDDArray;
..
end;
procedure TMat.SetSize(const RowSize, ColSize: Integer);
begin
SetLength(_Elem, RowSize, ColSize);
end;
function GetDynArrayRefCnt(const ADynArray): Longword;
begin
if Pointer(ADynArray) = nil then
Result := 1 {or 0, depending what you need}
else
Result := PLongword(Longword(ADynArray) - 8)^;
end;
procedure TMat.CopyElementsIfOthersRefer;
begin
if GetDynArrayRefCnt(_Elem) > 1 then
Self.Assign(Self);
end;
1 question intéressante. Je pense que je m'en tiendrai aux types de valeurs dans un enregistrement avec une surcharge de l'opérateur. –