全國最多中醫師線上諮詢網站-台灣中醫網
發文 回覆 瀏覽次數:1582
推到 Plurk!
推到 Facebook!

一些記憶體處理的觀念(含錯誤程式)

尚未結案
zombit
初階會員


發表:63
回覆:39
積分:30
註冊:2004-05-11

發送簡訊給我
#1 引用回覆 回覆 發表時間:2005-07-13 23:37:56 IP:61.62.xxx.xxx 未訂閱
一組 Record 如下,
  PRecord = ^TRecord;
  TRecord = record
    str: string;
    DateList: TList;
  end;
變數宣告 Var OneRecord: PRecord; OneRecord^ 是取 這個 PRecord 的 TRecord; Var OneRecord2: TRecord; @OneRecord2 是取他的 Pointer -------- OneRecord^ := OneRecord2; 將 OneRecord2 的內容拷貝到 OneRecord. (如何使用 Move 的寫法? 我用 Move(OneRecord2, OneRecord^, SizeOf(TRecord)); 不過怪怪的.. ) OneRecord := @OneRecord2; 記憶體空間的相等,兩者使用同一塊記憶體空間. OneRecord.Str := OneRecord2.Str; 是不是相等於 OneRecord^.Str := OneRecord2.Str -------- 我的問題程式說明 Form1 用於顯示 RecordList: TList 中加入的 PRecord, Form2 有一個 OneRecord: TRecord, 還有一個 Button, 每按下一次 Button, Form2.OneRecord 就填入 Str, Date 等值. 接著按 Form1 上的 Button, 顯示目前 RecordList 中所含的 PRecord. 問題在於每次加入 PRecord 後, Str 會更新, 但 DateList 的項目都是變成最新加入的那組. 很怪. 改變 Form2 的 日期後按下 Form2 的按鈕, 再到 Form1 按鈕, 你就看的出我的問題了 --------------- 我的問題在於 使用 OneRecord^ := OneRecord2; 這樣的方式, 是不是可以完全複製 OneRecord2的內容包含 DateList; 如果不行的話要怎麼處理? 整個 Record 一起複製, 不用 OneRecord^.xx := xxxx.xx 的方式, 一一指定 ----- 程式在 http://home.so-net.net.tw/aswater/tmp/TEST7.zip 請指教,謝謝.
malanlk
尊榮會員


發表:20
回覆:694
積分:577
註冊:2004-04-19

發送簡訊給我
#2 引用回覆 回覆 發表時間:2005-07-23 03:35:11 IP:61.219.xxx.xxx 未訂閱
問題出在  1.Form2 的 OneRecord ㄧ直都只有 ㄧ個 Instance, 所以 OneRecord.DataList 永遠都指向同ㄧ個 TList;  2.在做 OneRecord^ := Form2.OneRecord; 時只會將 Form2.OneRecord.DataList 的位址複製給 OneRecord^.DataList    因此 OneRecord^.DataList 都指到 Form2.OneRecord.DataList, 而Form2.OneRecord.DataList ㄧ直都只有ㄧ個 Instance. 也就是所有的OneRecord^.DataList 都指向同ㄧ個位置.    這個程式會不斷的吃記憶體哦, 因為 New 出來的 PDate 都沒 dispose 掉    正確的寫法 應該是  
// Form2 部分
type
  TForm2 = class(TForm)
    edt_1: TEdit;
    dtp1: TDateTimePicker;
    dtp2: TDateTimePicker;
    dtp3: TDateTimePicker;
    btn1: TButton;
    procedure btn1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject); // 釋放 Record
  private
    { Private declarations }
  public
    { Public declarations }
    OneRecord: PRecord;                     // 改用 Pointer
    procedure ClearOneRecord;
  end;    ...    implementation    procedure TForm2.btn1Click(Sender: TObject);
var
  aDate: PDate;
begin
  if (OneRecord=nil) then
  begin
    OneRecord := New(PRecord);          // 動態產生PRecord
    OneRecord.DateList := TList.Create; // 建立 PRecord.DataList        OneRecord.str := edt_1.Text;
    //OneRecord.DateList.Clear;         // 這行就免了        aDate := New(PDate);
    aDate^ := dtp1.Date;
    OneRecord.DateList.Add(aDate);        aDate := New(PDate);
    aDate^ := dtp2.Date;
    OneRecord.DateList.Add(aDate);        aDate := New(PDate);
    aDate^ := dtp3.Date;
    OneRecord.DateList.Add(aDate);
  end
  else
  begin
    OneRecord.str := edt_1.Text;
    PDate(OneRecord.DateList[0])^ := dtp1.Date;
    PDate(OneRecord.DateList[1])^ := dtp2.Date;
    PDate(OneRecord.DateList[2])^ := dtp3.Date;
  end;
end;    procedure TForm2.FormCreate(Sender: TObject);
begin
  OneRecord := nil;
  // OneRecord.DateList := TList.Create;  // 這行就不必了
end;    procedure TForm2.FormDestroy(Sender: TObject);
begin
  ClearOneRecord;
end;    procedure TForm2.ClearOneRecord;
begin
  if OneRecord<>nil then
  begin
    Dispose(PDate(OneRecord.DateList[0]));
    Dispose(PDate(OneRecord.DateList[1]));
    Dispose(PDate(OneRecord.DateList[2]));
    OneRecord.DateList.Clear;
    OneRecord.DateList.Free;
    Dispose(OneRecord);
    OneRecord := nil;
  end;
end;    // Form1 部分    function TForm1.Goupdating(): Boolean;
var
  i: Integer;
begin
  mmo_1.Clear;      for i := 0 to RecordList.Count - 1 do
  begin
    mmo_1.Lines.Add(TRecord(RecordList[i]^).Str);
    mmo_1.Lines.Add(DateToStr(TDate(TRecord(RecordList[i]^).DateList[0]^)));
    mmo_1.Lines.Add(DateToStr(TDate(TRecord(RecordList[i]^).DateList[1]^)));
    mmo_1.Lines.Add(DateToStr(TDate(TRecord(RecordList[i]^).DateList[2]^)));
  end;    end;    procedure TForm1.btn1Click(Sender: TObject);
var
  OneRecord: PRecord;
begin
  // 因為 Form2.OneRecord 是由 New 建立出來的
  // 所以直接交給 RecordList 就可以了
  RecordList.Add(Form2.OneRecord);
  Form2.OneRecord := nil;      //OneRecord := New(PRecord);
  //OneRecord.DateList := TList.Create;
  //OneRecord^ := Form2.OneRecord;
  // "如果不以上面三行複製就不爽"
  // Form2 中就要 保存 所有New 出來的 OneRecord
  // 不然 OneRecord^.DateList 會對不到
  // 這種情況通常是發生在希望保留原始資料,
  // 所以才要複製一份出來做處理時      Goupdating();
end;    procedure TForm1.FormCreate(Sender: TObject);
begin
  RecordList := TList.Create;
end;    procedure TForm1.FormShow(Sender: TObject);
begin
  Form2.Show;
end;    procedure TForm1.FormDestroy(Sender: TObject);
var
  i: Integer;
begin
  for i := 0 to RecordList.Count - 1 do
  begin
    Dispose(PDate(PRecord(RecordList[i]).DateList[0]));
    Dispose(PDate(PRecord(RecordList[i]).DateList[1]));
    Dispose(PDate(PRecord(RecordList[i]).DateList[2]));        PRecord(RecordList[i]).DateList.Clear;
    PRecord(RecordList[i]).DateList.Free;
    Dispose(PRecord(RecordList[i]));
  end;
  RecordList.Clear;
  RecordList.Free;
end;
有點懶, 沒寫的很清楚, 希望大家看的懂 發表人 - malanlk 於 2005/07/23 03:37:35
SamSam1230
中階會員


發表:128
回覆:178
積分:65
註冊:2004-12-23

發送簡訊給我
#3 引用回覆 回覆 發表時間:2005-07-25 10:12:43 IP:218.103.xxx.xxx 未訂閱
malanlk 講得已經很清楚, 再補充一點是, delphi Tlist, Tstringlist ,那些用於pointer 的關念 如果你是直接 A := B ,那只是 A pointer 指到 B 的地址而已, 並沒有把 B copy 到 A , 所以這裡要弄清楚, 要真正copy 過去要用它的assign 我也是剛學delphi , 講錯請其他大大改正 哈哈哈
系統時間:2024-05-09 0:00:36
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!