SIGSEGV beim Freigeben von Klasse

Für Fragen zur Programmiersprache auf welcher Lazarus aufbaut
PascalDragon
Beiträge: 825
Registriert: Mi 3. Jun 2020, 07:18
OS, Lazarus, FPC: L 2.0.8, FPC Trunk, OS Win/Linux
CPU-Target: Aarch64 bis Z80 ;)
Wohnort: München

Re: SIGSEGV beim Freigeben von Klasse

Beitrag von PascalDragon »

photor hat geschrieben:
So 21. Mär 2021, 17:13
Dann noch der Code zu:

Code: Alles auswählen

procedure TMainForm.ProcessTimeSeries(ts: TTimeSeries);
var
  fname: string;
  TS_minmax: TTimeSeries;
begin
  try
     // find min/max
    TS_minmax := Peak_n_Valley(ts);

    fname := TS_minmax.Name + '.txt';

    TS_minmax.SaveToFile(fname);
  finally
    TS_minmax.Free;
  end;
end;
Diese Prozedure sucht (im Moment nur nach Minima und Maxima in der übergebenen (einzelnen) TimeSeries, speichert die entsprechenden Signal-Zeitpunkte in einer neuen TimeSeries TS_minmax, die dann gespeichert wird. Zum Schluss wird die TS_minmax freigegeben (im weiteren Verlauf soll hier natürlich noch mehr mit passieren - also müsste ich die eigentlich auch wieder als Ergebnis zurück geben; das war aber für jetzt zu kompliziert).

... und dann noch (in einer eigenen Unit sb_defs.pas):

Code: Alles auswählen

function Peak_n_Valley(ts: TTimeSeries) : TTimeSeries;
var
  i: integer;
  spu, sp, spo: TSignalPoint;
begin
  result := TTimeSeries.Create;

  // add 1st data point to list
  sp := ts.Signal.First;
  result.Signal.Add(sp);

  // look for relative min and max in time series
  for i:=1 to ts.Signal.Count-2 do
  begin
    spu := ts.Signal.Items[i-1];
    sp := ts.Signal.Items[i];
    spo := ts.Signal.Items[i+1];

    if is_minmax(spu, sp, spo) then
      result.Signal.Add(sp);
  end;

  // add last data point
  sp := ts.Signal.Last;
  result.Signal.Add(sp);
  result.Name := ts.Name;

  // set number of entries in resulting TimeSeries
  result.NoEntries := result.Signal.Count;
end;

 function is_minmax(dpu, dp, dpo: TSignalPoint): boolean;
var
  diff1, diff2: double;
begin
  result := false;

  diff1 := dp.Value - dpu.Value;
  diff2 := dpo.Value - dp.Value;

  if (((diff1 > 0.0) and (diff2 < 0.0)) or         // rel. maximum
      ((diff1 < 0.0) and (diff2 > 0.0))) then      // rel. minimum
    result := true
end;  
Ah ha! Dein Problem ensteht in Peak_n_Valley: du nimmst die TSignalPoint Instanzen aus ts.Signal und fügst die in dein Result ein. Dieses gibst du dann in ProcessTimeSeries wieder frei und damit werden dann auch alle TSignalPoint Instanzen dort freigegeben was dann dazu führt, dass es beim Freigeben der Einträge in BoltTLS knallt. Du musst entweder neue TSignalPoint Instanzen anlegen (zum Beispiel über einen weiteren Konstruktor, der einen existierenden TSignalPoint annimmt und dann alle Felder kopiert) oder falls du es in der TTimeSeries nicht mehr brauchst über Extract herausnehmen ohne dass es freigegeben wird.
FPC Compiler Entwickler

Benutzeravatar
photor
Beiträge: 443
Registriert: Mo 24. Jan 2011, 21:38
OS, Lazarus, FPC: Arch Linux: L 2.2.6 FPC 3.2.2 (Gtk2)
CPU-Target: 64Bit

Re: SIGSEGV beim Freigeben von Klasse

Beitrag von photor »

Moin,

Ah! Wenn Du das so erklärst, klingt das logisch. Danke. Da habe ich gerade was verstanden und was gelernt!

Ich glaube, ich hätte da noch lange gesucht.

Ciao,
Photor

Warf
Beiträge: 1908
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: SIGSEGV beim Freigeben von Klasse

Beitrag von Warf »

Noch eine alternative, TObjectList bekommt im Kosntruktor soweit ich weiß einen Boolean (OwnsObjects oder so), wenn du eine Liste haben willst die die elemente nicht löscht wenn sie freigegeben wird einfach mit False erstellen. Somit kannst du den selben Listen typen benutzen mit und ohne Freigabe mechanismus

Benutzeravatar
photor
Beiträge: 443
Registriert: Mo 24. Jan 2011, 21:38
OS, Lazarus, FPC: Arch Linux: L 2.2.6 FPC 3.2.2 (Gtk2)
CPU-Target: 64Bit

Re: SIGSEGV beim Freigeben von Klasse

Beitrag von photor »

Moin,

darüber habe ich auch schon nachgedacht. entweder bei TObjectList OwnsElements = False setzen oder TList nutzen. Das macht es aber am Ende schwieriger, alles aufzuräumen, richtig?

Ich probiere es zunächst mit dem Neuerzeugen der Elemente in der neuen Liste (ist etwas umständlich und unelegant). Alternativ könnte man in der Originalliste alles raus werfen, was man nicht braucht - widerstrebt mir aber im Moment noch.

PS: auch wenn das gerade nicht mehr nötig ist, wollte ich doch auch versuchen, Valgrind als Debugger an's Rennen zu bekommen. Das ist aber ein neues Thema.

Ciao,
Photor

Antworten