Recent

Author Topic: memory management  (Read 1893 times)

srvaldez

  • Full Member
  • ***
  • Posts: 116
Re: memory management
« Reply #15 on: October 14, 2024, 01:15:44 pm »
wow  :D
thanks a million Thaddy  :)
this is exactly what I needed

Thaddy

  • Hero Member
  • *****
  • Posts: 16168
  • Censorship about opinions does not belong here.
Re: memory management
« Reply #16 on: October 14, 2024, 01:45:20 pm »
Glad to be of help. There are not many good examples on how to use the management operators yet so it was quite fun to write one.
If I smell bad code it usually is bad code and that includes my own code.

Thaddy

  • Hero Member
  • *****
  • Posts: 16168
  • Censorship about opinions does not belong here.
Re: memory management
« Reply #17 on: October 14, 2024, 02:32:59 pm »
[edit: removed copy and finalize]
[edit 2: restored copy, to do a deep copy. More in line with your intention]
Although my example above handles the general case of memory management, In your particular case I would write it like so:
Code: Pascal  [Select][+][-]
  1. program Project1;
  2.     {$mode objfpc}
  3.     {$modeswitch advancedrecords}
  4.  
  5.     {$warn 5089 off} { suppress uninitialized warning }
  6.     {$warn 5090 off} { suppress uninitialized warning }
  7.     {$warn 5092 off} { suppress uninitialized warning }
  8.     type
  9.       TLongintArray = array of Longint;
  10.       TRec = record
  11.       public
  12.         Value: TLongintArray;
  13.       strict private
  14.         class operator Initialize(var aRec: TRec);
  15.         class operator copy(constref a:TRec;var b:TRec);
  16.       public
  17.        { this operator should be public: it is not a management operator }
  18.        class operator = (const a,b:TRec):Boolean;
  19.       end;
  20.      
  21.     class operator TRec.Initialize(var aRec: TRec);
  22.     begin
  23.        ReturnNilIfGrowHeapFails := True;
  24.        SetLength(aRec.Value,1000);
  25.     end;
  26.    
  27.     class operator TRec.copy(constref a:TRec;var b:TRec);
  28.     begin
  29.       { make a deep copy, not a shallow - pointer - copy }
  30.       b.value:=Copy(a.value);
  31.     end;
  32.    
  33.     class operator TRec.= (const a,b:TRec):Boolean;
  34.     begin
  35.       { the records have the same content if the size is equal and the memory content is equal }
  36.       Result := (length(a.value) = length(b.value)) and (CompareDword(a.value[0],b.value[0],length(a.Value)) = 0);
  37.     end;
  38.  
  39.     procedure test(var a:TRec);
  40.     var b:TRec;
  41.         i:longint;
  42.     begin
  43.         writeln('b.value length = ', length(b.Value));
  44.         for i:=0 to length(b.value)-1 do
  45.         begin
  46.             b.Value[i]:=123+i;
  47.         end;  
  48.         a:=b; { assignment is copy on write, local var b is finalized on procedure exit. }
  49.     end;
  50.    
  51.  
  52.     var
  53.         t, z, x: TRec;    
  54.     begin
  55.       test(x);
  56.       writeln('t.value length = ', length(t.Value));
  57.       writeln('z.value length = ', Length(z.Value));
  58.       writeln('x.value length = ', Length(x.Value));
  59.       writeln('x.Value[0] = ', x.Value[0]);
  60.       writeln('x.Value[1] = ', x.Value[1]);
  61.       writeln('x.Value[2] = ', x.Value[2]);
  62.       writeln('x.Value[',1000-3,'] = ', x.Value[1000-3]);
  63.       writeln('x.Value[',1000-2,'] = ', x.Value[1000-2]);
  64.       writeln('x.Value[',1000-1,'] = ', x.Value[1000-1]);
  65.       t:=x; { assignment is copy on write }
  66.       writeln('Is the content of t equal to that of x after assignment? ',t = x);
  67.       writeln('t.Value[',1000-3,'] = ', t.Value[1000-3]);
  68.       writeln('t.Value[',1000-2,'] = ', t.Value[1000-2]);
  69.       writeln('t.Value[',1000-1,'] = ', t.Value[1000-1]);    
  70.       { change x value and check t}
  71.       x.value[0] := 10000;
  72.       writeln(t.value[0]);
  73.          
  74.       readln;
  75.     end.
This is just an alternative approach that makes it more difficult for pointer errors to occur.
It is otherwise functionally equivalent, but does not require manual memory management.
See that size is gone and the finalize operator disappeared? As did all the pointer handling?
A dynamic array is a managed type, so memory management is automatic.

If this is your use case, do it like so.
In FreePascal, pointers are not cool... %)
« Last Edit: October 14, 2024, 03:58:52 pm by Thaddy »
If I smell bad code it usually is bad code and that includes my own code.

srvaldez

  • Full Member
  • ***
  • Posts: 116
Re: memory management
« Reply #18 on: October 14, 2024, 05:06:55 pm »
thanks again Thaddy  :D
as an exercise I adapted the code provided by Thaddy to the Mparith mpf_float, if you need to get Mparith you may get it from https://forum.lazarus.freepascal.org/index.php/topic,68447.msg528998.html
note: I used Thaddy's previous posted code
please let me know of any corrections needed
Code: Pascal  [Select][+][-]
  1. program mp_test;
  2.     {$mode objfpc}
  3.     {$modeswitch advancedrecords}
  4.  
  5.     {$warn 5089 off} //suppress uninitialized warning
  6.     {$warn 5090 off} //suppress uninitialized warning
  7.     {$warn 5092 off} //suppress uninitialized warning
  8.     {$warn 5025 off} //suppress variable not used warning
  9.     {$warn 4055 off} //suppress not portable
  10.    
  11. uses
  12.     mp_types, btypes, mp_real, mp_base, mp_numth, mp_calc, sysutils, windows, math, strings, JwaWinBase;
  13.  
  14. const default_prec=125;
  15. const print_prec=80;
  16.  
  17.     type
  18.         mpfloat = record
  19.         public
  20.         mpf: mp_float;
  21.         strict private
  22.         class operator Initialize(var aRec: mpfloat);
  23.         class operator Finalize(var aRec: mpfloat);
  24.         class operator Copy(constref cFrom:mpfloat; var cTo:mpfloat);
  25.         public
  26.         class operator < (const a,b:mpfloat):Boolean;
  27.         class operator <= (const a,b:mpfloat):Boolean;
  28.         class operator > (const a,b:mpfloat):Boolean;
  29.         class operator >= (const a,b:mpfloat):Boolean;
  30.         class operator <> (const a,b:mpfloat):Boolean;
  31.         class operator = (const a,b:mpfloat):Boolean;
  32.         end;
  33.      
  34.     class operator mpfloat.Initialize(var aRec: mpfloat);
  35.     begin
  36.         ReturnNilIfGrowHeapFails := True;
  37.         mpf_set_default_prec(round(default_prec*3.321928094887362));
  38.         mpf_init(aRec.mpf);
  39.     end;
  40.  
  41.     class operator mpfloat.Finalize(var aRec: mpfloat);
  42.     begin
  43.         mpf_clear(aRec.mpf);
  44.     end;
  45.  
  46.     class operator mpfloat.Copy(constref cFrom:mpfloat;var cTo:mpfloat);
  47.     begin
  48.         mpf_clear(cTo.mpf);
  49.         mpf_set_default_prec(round(default_prec*3.321928094887362));
  50.         mpf_init(cTo.mpf);
  51.         mpf_copy(cFrom.mpf, cTo.mpf);
  52.     end;
  53.  
  54. //----------------------------------------------------------------
  55.  
  56.     procedure writelnq(const n:mpfloat; const digits : longint=80);
  57.     begin
  58.         if s_mpf_is_neg(n.mpf) then
  59.         begin
  60.             mpf_output_decimal(n.mpf, digits);
  61.             writeln;
  62.         end
  63.         else
  64.         begin
  65.             write(' ');
  66.             mpf_output_decimal(n.mpf, digits);
  67.             writeln;
  68.         end;
  69.     end;
  70.    
  71.     procedure writeq(const n:mpfloat; const digits : longint=80);
  72.     begin
  73.         if s_mpf_is_neg(n.mpf) then
  74.             mpf_output_decimal(n.mpf, digits)
  75.         else
  76.         begin
  77.             write(' ');
  78.             mpf_output_decimal(n.mpf, digits);
  79.         end;
  80.     end;
  81.  
  82.     operator := (const r : pchar8) z : mpfloat;  
  83.      
  84.     begin
  85.         mpf_read_decimal(z.mpf, r);
  86.     end;
  87.    
  88.     operator := (const r : longint) z : mpfloat;  
  89.      
  90.     begin
  91.         mpf_set_int(z.mpf, r);
  92.     end;
  93.    
  94.     operator := (const r : double) z : mpfloat;  
  95.      
  96.     begin
  97.         mpf_set_dbl(z.mpf, r);
  98.     end;
  99.    
  100.     operator + (const x : mpfloat; const y : mpfloat) z : mpfloat;  
  101.      
  102.     begin
  103.         mpf_add(x.mpf, y.mpf, z.mpf);
  104.     end;
  105.    
  106.     operator - (const x : mpfloat; const y : mpfloat) z : mpfloat;  
  107.      
  108.     begin
  109.         mpf_sub(x.mpf, y.mpf, z.mpf);
  110.     end;
  111.  
  112.     operator * (const x : mpfloat; const y : mpfloat) z : mpfloat;  
  113.      
  114.     begin
  115.       mpf_mul(x.mpf, y.mpf, z.mpf);
  116.     end;
  117.  
  118.     operator * (const x : mpfloat; const y : longint) z : mpfloat;  
  119.      
  120.     begin
  121.       mpf_mul_int(x.mpf, y, z.mpf);
  122.     end;
  123.  
  124.     operator * (const x : longint; const y : mpfloat ) z : mpfloat;  
  125.     var r:mpfloat;
  126.     begin
  127.         mpf_set_int(r.mpf, x);
  128.       mpf_mul(r.mpf, y.mpf, z.mpf);
  129.     end;
  130.    
  131.     operator / (const x : mpfloat; const y : mpfloat) z : mpfloat;  
  132.      
  133.     begin
  134.       mpf_div(x.mpf, y.mpf, z.mpf);
  135.     end;
  136.  
  137.     operator / (const x : mpfloat; const y : longint) z : mpfloat;  
  138.      
  139.     begin
  140.       mpf_div_int(x.mpf, y, z.mpf);
  141.     end;
  142.    
  143.     operator / (const x : longint; const y : mpfloat ) z : mpfloat;  
  144.     var r:mpfloat;
  145.     begin
  146.         mpf_set_int(r.mpf, x);
  147.       mpf_div(r.mpf, y.mpf, z.mpf);
  148.     end;
  149.    
  150.     class operator mpfloat.< (const a,b:mpfloat):Boolean;
  151.     begin  
  152.       result:=(mpf_cmp(a.mpf, b.mpf)<0);
  153.     end;
  154.    
  155.     class operator mpfloat.<= (const a,b:mpfloat):Boolean;
  156.     begin  
  157.       result:=(mpf_cmp(a.mpf, b.mpf)<=0);
  158.     end;
  159.    
  160.     class operator mpfloat.> (const a,b:mpfloat):Boolean;  
  161.     begin  
  162.       result:=(mpf_cmp(a.mpf, b.mpf)>0);
  163.     end;
  164.    
  165.     class operator mpfloat.>= (const a,b:mpfloat):Boolean;  
  166.     begin  
  167.       result:=(mpf_cmp(a.mpf, b.mpf)>=0);
  168.     end;
  169.    
  170.     class operator mpfloat.<> (const a,b:mpfloat):Boolean;
  171.     begin  
  172.       result:=(mpf_cmp(a.mpf, b.mpf)<>0);
  173.     end;
  174.    
  175.     class operator mpfloat.= (const a,b:mpfloat):Boolean;
  176.     begin  
  177.       result:=(mpf_cmp(a.mpf, b.mpf)=0);
  178.     end;
  179.  
  180.     function sqrt(const x : mpfloat):mpfloat;
  181.     begin
  182.         mpf_sqrt(x.mpf, sqrt.mpf);
  183.     end;
  184.    
  185.     function sin(const x : mpfloat): mpfloat;
  186.     begin
  187.         mpf_sin(x.mpf, sin.mpf);
  188.     end;
  189.    
  190.     function cos(const x : mpfloat): mpfloat;
  191.     begin
  192.         mpf_cos(x.mpf, cos.mpf);
  193.     end;
  194.    
  195.     function tan(const x : mpfloat): mpfloat;
  196.     begin
  197.         mpf_tan(x.mpf, tan.mpf);
  198.     end;
  199.  
  200.     function arcsin(const x : mpfloat): mpfloat;
  201.     begin
  202.         mpf_arcsin(x.mpf, arcsin.mpf);
  203.     end;
  204.    
  205.     function arccos(const x : mpfloat): mpfloat;
  206.     begin
  207.         mpf_arccos(x.mpf, arccos.mpf);
  208.     end;
  209.    
  210.     function arctan(const x : mpfloat): mpfloat;
  211.     begin
  212.         mpf_arctan(x.mpf, arctan.mpf);
  213.     end;
  214.    
  215.     function log(const x : mpfloat): mpfloat;
  216.     begin
  217.         mpf_ln(x.mpf, log.mpf);
  218.     end;
  219.    
  220.     function exp(const x : mpfloat): mpfloat;
  221.     begin
  222.         mpf_exp(x.mpf, exp.mpf);
  223.     end;
  224.    
  225.     function abs(const x : mpfloat): mpfloat;
  226.     begin
  227.         mpf_abs(x.mpf, abs.mpf);
  228.     end;
  229.  
  230. //=============================================================
  231.  
  232. const n = 50;
  233.  
  234. var
  235.     start_time,
  236.     end_time        :int32;
  237.     delta, t        :double;
  238.     b: array[0..n] of mpfloat;
  239.     c: array[0..n] of mpfloat;
  240.     one, tmp : mpfloat;
  241.     i, j : longint;
  242.  
  243. begin
  244.     //---------------------------------------------------------
  245.     // Akiyama–Tanigawa algorithm for Bn
  246.     //---------------------------------------------------------
  247.  
  248.     t:=round((n+print_prec)*0.96);
  249.     if (round(t/8)*8)<t then
  250.         t:=(round(t/8)+1)*8;
  251.  
  252.     if default_prec<t then
  253.     begin
  254.         writeln('for ',n,' bernoulli numbers at ',print_prec,' digits of precision you need ',t,' digits of precision');
  255.     end
  256.     else
  257.     begin
  258.         start_time:= GetTickCount64;
  259.  
  260.         one := 1;
  261.         For i := 0 To n do
  262.         begin
  263.             c[i] := one / (i+1);
  264.             For j := i downTo 1 do
  265.             begin
  266.                 tmp:=c[j - 1]-c[j];
  267.                 c[j - 1] := tmp * j;
  268.             end;
  269.             b[i]:=c[0];
  270.         end;
  271.         end_time:= GetTickCount64;
  272.         For i := 0 To n do
  273.         begin
  274.             if i>2 then
  275.             begin
  276.                 if (i and 1)=0 then
  277.                 begin
  278.                     write('B[',i:2,'] = '); writelnq(b[i], print_prec);
  279.                 end;
  280.             end
  281.             else
  282.             begin
  283.                 write('B[',i:2,'] = '); writelnq(b[i], print_prec);
  284.             end;
  285.         end;
  286.         delta:= (end_time - start_time) / 1000;
  287.         writeln('time elapsed is ', delta:1:6, ' seconds');
  288.     end;
  289. end.
  290.  

Thaddy

  • Hero Member
  • *****
  • Posts: 16168
  • Censorship about opinions does not belong here.
Re: memory management
« Reply #19 on: October 14, 2024, 05:25:20 pm »
That looks fine to me. Maybe some details, but not necessary. It is proper code.
If I smell bad code it usually is bad code and that includes my own code.

srvaldez

  • Full Member
  • ***
  • Posts: 116
Re: memory management
« Reply #20 on: October 14, 2024, 06:50:59 pm »
thanks Thaddy
here's the rational
Code: Pascal  [Select][+][-]
  1. program mp_test;
  2.     {$mode objfpc}
  3.     {$modeswitch advancedrecords}
  4.  
  5.     {$warn 5089 off} //suppress uninitialized warning
  6.     {$warn 5090 off} //suppress uninitialized warning
  7.     {$warn 5092 off} //suppress uninitialized warning
  8.     {$warn 5025 off} //suppress variable not used warning
  9.     {$warn 4055 off} //suppress not portable
  10.    
  11. uses
  12.     mp_types, btypes, mp_real, mp_ratio, mp_base, mp_numth, mp_calc, sysutils, windows, math, strings, JwaWinBase;
  13.  
  14.     type
  15.         BigRat = record
  16.         public
  17.         mpr: mp_rat;
  18.         strict private
  19.         class operator Initialize(var aRec: BigRat);
  20.         class operator Finalize(var aRec: BigRat);
  21.         class operator Copy(constref cFrom:BigRat; var cTo:BigRat);
  22.         public
  23.         class operator < (const a,b:BigRat):Boolean;
  24.         class operator <= (const a,b:BigRat):Boolean;
  25.         class operator > (const a,b:BigRat):Boolean;
  26.         class operator >= (const a,b:BigRat):Boolean;
  27.         class operator <> (const a,b:BigRat):Boolean;
  28.         class operator = (const a,b:BigRat):Boolean;
  29.         end;
  30.      
  31.     class operator BigRat.Initialize(var aRec: BigRat);
  32.     begin
  33.         ReturnNilIfGrowHeapFails := True;
  34.         mpr_init(aRec.mpr);
  35.     end;
  36.  
  37.     class operator BigRat.Finalize(var aRec: BigRat);
  38.     begin
  39.         mpr_clear(aRec.mpr);
  40.     end;
  41.  
  42.     class operator BigRat.Copy(constref cFrom:BigRat;var cTo:BigRat);
  43.     begin
  44.         mpr_clear(cTo.mpr);
  45.         mpr_init(cTo.mpr);
  46.         mpr_copy(cFrom.mpr, cTo.mpr);
  47.     end;
  48.  
  49. //----------------------------------------------------------------
  50.  
  51.     procedure writelnq(const n:BigRat);
  52.     begin
  53.         if n.mpr.num.sign=MP_NEG then
  54.         begin
  55.             mpr_output_decimal(n.mpr);
  56.             writeln;
  57.         end
  58.         else
  59.         begin
  60.             write(' ');
  61.             mpr_output_decimal(n.mpr);
  62.             writeln;
  63.         end;
  64.     end;
  65.    
  66.     procedure writeq(const n:BigRat);
  67.     begin
  68.         if n.mpr.num.sign=MP_NEG then
  69.             mpr_output_decimal(n.mpr)
  70.         else
  71.         begin
  72.             write(' ');
  73.             mpr_output_decimal(n.mpr);
  74.         end;
  75.     end;
  76.  
  77.     operator := (const r : pchar8) z : BigRat;  
  78.      
  79.     begin
  80.         mpr_read_decimal(z.mpr, r);
  81.     end;
  82.    
  83.     operator := (const r : longint) z : BigRat;  
  84.      
  85.     begin
  86.         mpr_set_int(z.mpr, r, 1);
  87.     end;
  88.    
  89.     operator + (const x : BigRat; const y : BigRat) z : BigRat;  
  90.      
  91.     begin
  92.         mpr_add(x.mpr, y.mpr, z.mpr);
  93.     end;
  94.    
  95.     operator - (const x : BigRat) z : BigRat;  
  96.      
  97.     begin
  98.         mpr_copy(x.mpr, z.mpr);
  99.         z.mpr.num.sign:=1-z.mpr.num.sign;
  100.     end;
  101.    
  102.     operator - (const x : BigRat; const y : BigRat) z : BigRat;  
  103.      
  104.     begin
  105.         mpr_sub(x.mpr, y.mpr, z.mpr);
  106.     end;
  107.  
  108.     operator * (const x : BigRat; const y : BigRat) z : BigRat;  
  109.      
  110.     begin
  111.       mpr_mul(x.mpr, y.mpr, z.mpr);
  112.     end;
  113.  
  114.     operator * (const x : BigRat; const y : longint) z : BigRat;  
  115.      
  116.     begin
  117.       mpr_mul_int(x.mpr, y, z.mpr);
  118.     end;
  119.    
  120.     operator / (const x : BigRat; const y : BigRat) z : BigRat;  
  121.      
  122.     begin
  123.       mpr_div(x.mpr, y.mpr, z.mpr);
  124.     end;
  125.    
  126.     class operator BigRat.< (const a,b:BigRat):Boolean;
  127.     begin  
  128.       result:=(mpr_cmp(a.mpr, b.mpr)<0);
  129.     end;
  130.    
  131.     class operator BigRat.<= (const a,b:BigRat):Boolean;
  132.     begin  
  133.       result:=(mpr_cmp(a.mpr, b.mpr)<=0);
  134.     end;
  135.    
  136.     class operator BigRat.> (const a,b:BigRat):Boolean;  
  137.     begin  
  138.       result:=(mpr_cmp(a.mpr, b.mpr)>0);
  139.     end;
  140.    
  141.     class operator BigRat.>= (const a,b:BigRat):Boolean;  
  142.     begin  
  143.       result:=(mpr_cmp(a.mpr, b.mpr)>=0);
  144.     end;
  145.    
  146.     class operator BigRat.<> (const a,b:BigRat):Boolean;
  147.     begin  
  148.       result:=(mpr_cmp(a.mpr, b.mpr)<>0);
  149.     end;
  150.    
  151.     class operator BigRat.= (const a,b:BigRat):Boolean;
  152.     begin  
  153.       result:=(mpr_cmp(a.mpr, b.mpr)=0);
  154.     end;
  155.    
  156.     function abs(const x : BigRat): BigRat;
  157.     begin
  158.         mpr_abs(x.mpr, abs.mpr);
  159.     end;
  160.  
  161. //=============================================================
  162.  
  163. const n = 99;
  164.  
  165. var
  166.     start_time,
  167.     end_time        :int32;
  168.     delta           :double;
  169.     b: array[0..n] of BigRat;
  170.     c: array[0..n] of BigRat;
  171.     one, tmp : BigRat;
  172.     i, j : longint;
  173.  
  174. begin
  175.     //---------------------------------------------------------
  176.     // Akiyama–Tanigawa algorithm for Bn
  177.     //---------------------------------------------------------
  178.  
  179.     begin
  180.         start_time:= GetTickCount64;
  181.  
  182.         one := 1;
  183.         For i := 0 To n do
  184.         begin
  185.             c[i] := one / (i+1);
  186.             For j := i downTo 1 do
  187.             begin
  188.                 tmp:=c[j - 1]-c[j];
  189.                 c[j - 1] := tmp * j;
  190.             end;
  191.             b[i]:=c[0];
  192.         end;
  193.         end_time:= GetTickCount64;
  194.         For i := 0 To n do
  195.         begin
  196.             if i>2 then
  197.             begin
  198.                 if (i and 1)=0 then
  199.                 begin
  200.                     write('B[',i:2,'] = '); writelnq(b[i]);
  201.                 end;
  202.             end
  203.             else
  204.             begin
  205.                 write('B[',i:2,'] = '); writelnq(b[i]);
  206.             end;
  207.         end;
  208.         delta:= (end_time - start_time) / 1000;
  209.         writeln('time elapsed is ', delta:1:6, ' seconds');
  210.     end;
  211. end.
  212.  
« Last Edit: October 14, 2024, 07:00:36 pm by srvaldez »

PascalDragon

  • Hero Member
  • *****
  • Posts: 5755
  • Compiler Developer
Re: memory management
« Reply #21 on: October 14, 2024, 10:19:57 pm »
Debugger shows its initialized just by existing in the var.

But perhaps you could add extra Default() here for safety, Im not sure how these auto-initialized record works. You need more reading 8)

Code: Pascal  [Select][+][-]
  1. class operator TRec.Initialize(var aRec: TRec);
  2. begin
  3.   aRec := Default(TRec);
  4.   // ...
  5. end;

DON'T!

Default() initializes a variable to its initial state, thus it needs to essentially call the Initialize-operator as well, thus you using Default() inside said operator will lead to problems. At least from 3.3.1 on, because 3.2.x has a bug that it doesn't call the Initialize-operator which has been fixed last week.


Management operators should always be strict private.


There is no “should” for the visiblity of management operators, cause one can't call them manually anyway.

Bart

  • Hero Member
  • *****
  • Posts: 5465
    • Bart en Mariska's Webstek
Re: memory management
« Reply #22 on: October 14, 2024, 10:29:48 pm »
DON'T!

Default() initializes a variable to its initial state, thus it needs to essentially call the Initialize-operator as well, thus you using Default() inside said operator will lead to problems. At least from 3.3.1 on, because 3.2.x has a bug that it doesn't call the Initialize-operator which has been fixed last week.

Am I correct when I conclude that the example on Initialize in the wiki is wrong then?
Part of the example:
Code: Pascal  [Select][+][-]
  1. class operator TRec.Initialize(var aRec: TRec);
  2. begin
  3.   aRec := Default(TRec); // initialize to default
  4. end;

Bart

Thaddy

  • Hero Member
  • *****
  • Posts: 16168
  • Censorship about opinions does not belong here.
Re: memory management
« Reply #23 on: October 15, 2024, 05:11:54 am »
Yes. Not only that example. I used in some more places. Will fix the entries that I wrote.
« Last Edit: October 15, 2024, 06:18:34 am by Thaddy »
If I smell bad code it usually is bad code and that includes my own code.

Thaddy

  • Hero Member
  • *****
  • Posts: 16168
  • Censorship about opinions does not belong here.
Re: memory management
« Reply #24 on: October 15, 2024, 07:32:03 am »
DON'T!
There is no “should” for the visiblity of management operators, cause one can't call them manually anyway.
Yes. My observation is that initialize was called somewhere in the above code, but that is the other initialize, the one from system. The one who wrote that code was probably not aware of that and it initially confused me too. Indeed, you can not call the management operators directly. (but it does not hurt to make them strict protected anyway, from a notational point of view.)

Here's a contrived example what happened:
Code: Pascal  [Select][+][-]
  1. program initbug;
  2. { intentionally buggy code!! }
  3. {$mode objfpc}{$modeswitch advancedrecords}
  4. type
  5.   TSomeRec=record
  6.   a:pinteger;
  7.   class procedure init(var value:TSomeRec);static;
  8.   class operator initialize(var value:TSomeRec);
  9.   class operator finalize(var value:TSomeRec);
  10.   end;
  11.  
  12.   class operator TSomeRec.initialize(var value:TSomeRec);
  13.   begin
  14.     writeln('Initialized' );
  15.     value.a := allocmem(1000);
  16.   end;
  17.  
  18.   class operator TSomeRec.finalize(var value:TSomeRec);
  19.   begin
  20.     writeln('Finalized' );
  21.     FreeMem(value.a);
  22.   end;
  23.  
  24.   class procedure TSomeRec.Init(var value:TSomeRec);
  25.   begin
  26.   { HERE'S THE BUG:
  27.     This is not the management operator, but system.initialize ,
  28.     which in turn calls the management operator again.}
  29.     Initialize(value);
  30.   end;
  31.  
  32. var
  33.   Rec:TSomeRec;
  34. begin
  35.   Rec.init(rec);
  36.  
  37. end.
This outputs:
Code: Bash  [Select][+][-]
  1. Initialized
  2. Initialized
  3. Finalized
  4. Heap dump by heaptrc unit of "d:\initbug.exe"
  5. 2 memory blocks allocated : 2000/2000
  6. 1 memory blocks freed     : 1000/1000
  7. 1 unfreed memory blocks : 1000
  8. True heap size : 393216 (96 used in System startup)
  9. True free heap : 391872
  10. Should be : 391928
  11. Call trace for block $00000000016135A0 size 1000
  12.   $000000010000DE5B
  13.   $000000010000615B
  14.   $000000010000162F  initialize,  line 14 of initbug.pas
  15.   $0000000100005467
  16.   $000000010000596D
  17.   $00000001000016AA  main,  line 30 of initbug.pas
  18.   $0000000100001F96
  19.   $000000010000A380
  20.   $00000001000015E0
  21.   $00007FFE65CF7374
  22.   $00007FFE65E9CC91

System.initialize causes the management operator initialize  to be called, so it is called twice, introducing a memory leak.
That is what happened somewhere above. Calling system.Finalize makes it even worse.

And that was the kind of bug I fixed in my two examples.
I very much doubt that many would spot that immediately.
There are multiple ways to recreate this kind of bug, not only the above example perse.
« Last Edit: October 15, 2024, 08:06:22 am by Thaddy »
If I smell bad code it usually is bad code and that includes my own code.

PascalDragon

  • Hero Member
  • *****
  • Posts: 5755
  • Compiler Developer
Re: memory management
« Reply #25 on: October 17, 2024, 09:28:59 pm »
Am I correct when I conclude that the example on Initialize in the wiki is wrong then?

That is indeed the case.

Thaddy

  • Hero Member
  • *****
  • Posts: 16168
  • Censorship about opinions does not belong here.
Re: memory management
« Reply #26 on: October 18, 2024, 05:55:57 am »
I wrote most of that, so I fixed it with some explanation.
If I smell bad code it usually is bad code and that includes my own code.

 

TinyPortal © 2005-2018