Суммирование:
Для функции / процедуры Delphi, если экземпляр класса передается в качестве аргумента, создается другая ссылка (помимо исходной ссылки) на временный стек вызовов для указанияк этому экземпляру и используется локально.Таким образом, будьте осторожны:
(1) Если функция / процедура хочет только изменить содержимое / поля / свойства этого экземпляра, префикс var не требуется;
(2) Если функция / процедура, вероятно, хочет переназначить ссылку на новый экземпляр, используйте префикс var, или это временная ссылка, которая будет переназначена.
(3) Обратите внимание, что если функция / процедура переназначает ссылку, а префикс var не используется, результат, вероятно, будет правильным, что еще хуже, потому что когда-нибудь код сломается.
=============================================
Ситуация:
Это небольшое приложение.TMolForm является формой MDIChild, и каждый TMolForm содержит TMolScene, который происходит от TPaintBox.TMolScene рисует TMol.В процедуре рисования TMolScene TMolScene вызывает TMol.Rescale, если TMolScene изменяется.Затем TMolScene вызывает TMol.TransformCoordinates для построения координат для последующего рендеринга.
Проблема заключается в следующем:
Теперь в TMol.Rescale я сбрасываю матрицы, пропущенные вызывающей стороной TMolScene.Однако я встречаю исключения, которые не могу придумать причину.
(1) В частности, если у меня есть множественный TMolForm и быстро , делайте изменение размера, перетаскивание мышью (вращение молекулы), переключение между TMolForm, менее чем заЧерез 5 минут матрицы (предположительно уже сброшенные в TMol.Rescale) передаются в TMol.TransformCoordinates равны нулю или содержат нулевое содержимое.
(2) Если я включу FastMM4 и его FullDebugMode, и повторю вышеуказанные движения мыши, я могу получить «TMol.Rescale пытается освободить освобожденный объект».Похоже, что TMol.Rescale вызывается снова, когда последний вызов (или последний цикл рисования) не завершен.Я имею в виду, что я не делал никаких попыток, связанных с многопоточностью, как возможно, что TMol.Rescale может быть вызван во второй раз, когда последний вызов еще не возвращается?Я полностью потерян.Не могли бы вы помочь прокомментировать возможные причины?
(3) Если я удаляю сброс матриц из TMol.Rescale и в вызывающую его, TMolScene.OnScenePaint, исключения, похоже, не произойдут, по крайней мере, через 5 минут.(Я не быстро не злоупотреблял мышью дольше 5 минут. Возможно, есть другой лучший способ тестирования.) Я понятия не имею, почему это работает и почему вышеупомянутые сбои иногда .
(4) Если у меня есть только один TMolform, вышеупомянутые исключения, по-видимому, не произойдут, по крайней мере, через 5 минут.
Я должен признать, что я составил следующий свернутый код, чтобылови исключения.Однако, хотя процедура выполнения должна отражать реальную ситуацию, исключения не происходят.Если вы хотите увидеть реальный код, который я хочу отправить вам по электронной почте или другим способом.Это хобби и не хорошо написано, хотя, извините.
Любые предложения, касающиеся исключений или плохих привычек кодирования, действительно приветствуются.
unit uMolForm;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
ExtCtrls, Dialogs;
type
TVec = class;
TMat = class;
TMol = class;
TMolScene = class;
TMolForm = class;
TVec = class
public
X, Y, Z: Extended;
constructor Create; overload;
constructor Create(aX, aY, aZ: Extended); overload;
end;
TMat = class
private
FX, FY, FZ, FT: TVec;
public
property X: TVec read FX;
property Y: TVec read FY;
property Z: TVec read FZ;
constructor Create;
destructor Destroy; override;
function ToUnit: TMat;
end;
TMol = class
public
constructor Create;
destructor Destroy; override;
procedure Rescale(aBbWidth, aBbHeight: Integer;
aRotationMatUser, aTranslationMatUser, aScalingMatUser: TMat);
procedure TransformCoordinates(aBbWidth, aBbHeight: Integer;
aRotationMatUser, aTranslationMatUser, aScalingMatUser: TMat);
end;
TMolScene = class(TPaintBox)
private
FBbWidth, FBbHeight: Integer;
FRotationMat, FTranslationMat, FScalingMat: TMat;
FMol: TMol;
procedure OnScenePaint(Sender: TObject);
procedure OnSceneMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure OnSceneMouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure OnSceneMouseMove(Sender: TObject; Shift: TShiftState;
X, Y: Integer);
public
constructor Create(AOwner: TComponent);
destructor Destroy; override;
end;
TMolForm = class(TForm)
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
FMolScene: TMolScene;
public
{ Public declarations }
end;
implementation
{$R *.dfm}
{ TVec }
constructor TVec.Create;
begin
inherited;
X := 0;
Y := 0;
Z := 0;
end;
constructor TVec.Create(aX, aY, aZ: Extended);
begin
inherited Create;
X := aX;
Y := aY;
Z := aZ;
end;
{ TMat }
constructor TMat.Create;
begin
inherited;
ToUnit;
end;
destructor TMat.Destroy;
begin
FreeAndNil(FX);
FreeAndNil(FY);
FreeAndNil(FZ);
FreeAndNil(FT);
inherited;
end;
function TMat.ToUnit: TMat;
begin
FreeAndNil(FX);
FreeAndNil(FY);
FreeAndNil(FZ);
FreeAndNil(FT);
FX := TVec.Create(1, 0, 0);
FY := TVec.Create(0, 1, 0);
FZ := TVec.Create(0, 0, 1);
FT := TVec.Create;
Result := Self;
end;
{ TMol }
constructor TMol.Create;
begin
inherited;
end;
destructor TMol.Destroy;
begin
inherited;
end;
procedure TMol.Rescale(aBbWidth, aBbHeight: Integer;
aRotationMatUser, aTranslationMatUser, aScalingMatUser: TMat);
begin
FreeAndNil(aRotationMatUser);
FreeAndNil(aTranslationMatUser);
FreeAndNil(aScalingMatUser);
aRotationMatUser := TMat.Create;
aTranslationMatUser := TMat.Create;
aScalingMatUser := TMat.Create;
end;
procedure TMol.TransformCoordinates(aBbWidth, aBbHeight: Integer;
aRotationMatUser, aTranslationMatUser, aScalingMatUser: TMat);
begin
if (aRotationMatUser.X = nil) or (aRotationMatUser.Y = nil) or
(aRotationMatUser.Z = nil) or (aTranslationMatUser.X = nil) or
(aTranslationMatUser.Y = nil) or (aTranslationMatUser.Z = nil) or
(aScalingMatUser.X = nil) or (aScalingMatUser.Y = nil) or
(aScalingMatUser.Z = nil) then
begin
raise Exception.Create('what happened?!');
end;
end;
{ TMolScene }
constructor TMolScene.Create(AOwner: TComponent);
begin
inherited;
FRotationMat := TMat.Create;
FTranslationMat := TMat.Create;
FScalingMat := TMat.Create;
FMol := TMol.Create;
Self.OnPaint := Self.OnScenePaint;
Self.OnMouseDown := Self.OnSceneMouseDown;
Self.OnMouseUp := Self.OnSceneMouseUp;
Self.OnMouseMove := Self.OnSceneMouseMove;
end;
destructor TMolScene.Destroy;
begin
FreeAndNil(FRotationMat);
FreeAndNil(FTranslationMat);
FreeAndNil(FScalingMat);
FreeAndNil(FMol);
inherited;
end;
procedure TMolScene.OnScenePaint(Sender: TObject);
begin
if (FBbWidth <> Self.ClientWidth) or (FBbHeight <> Self.ClientHeight) then
begin
FBbWidth := Self.ClientWidth;
FBbHeight := Self.ClientHeight;
FMol.Rescale(FBbWidth, FBbHeight, FRotationMat, FTranslationMat,
FScalingMat);
end;
FMol.TransformCoordinates(FBbWidth, FBbHeight, FRotationMat, FTranslationMat,
FScalingMat);
end;
procedure TMolScene.OnSceneMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
Self.Repaint;
end;
procedure TMolScene.OnSceneMouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
Self.Repaint;
end;
procedure TMolScene.OnSceneMouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
begin
Self.Repaint;
end;
{ TMolForm }
procedure TMolForm.FormCreate(Sender: TObject);
begin
FMolScene := TMolScene.Create(Self);
FMolScene.Parent := Self;
FMolScene.Align := alClient;
end;
procedure TMolForm.FormClose(Sender: TObject; var Action: TCloseAction);
begin
Action := caFree;
end;
end.