Recent

Author Topic: AV in operator overloading  (Read 656 times)

fcu

  • Full Member
  • ***
  • Posts: 118
AV in operator overloading
« on: May 27, 2025, 09:31:09 am »
Hi
if you run this example you'll get AV ,obviously its accessing pointer before initializing it ,
but in this example i do initializing it , so i am a bit confused !
Code: Pascal  [Select][+][-]
  1. program test;
  2. {$ifdef FPC}{$mode objfpc}{$h+}{$endif}
  3. {$ifdef mswindows}{$apptype console}{$endif}
  4. {$modeswitch advancedrecords}
  5. uses
  6.  {$ifdef FPC}{$ifdef unix}cthreads,cwstring,{$endif}{$endif}
  7.  sysutils;
  8.  
  9.  
  10. type
  11.  trec = record
  12.   public
  13.    data : pint32;
  14.   public
  15.    procedure initptr(v: int32);
  16.    procedure freeptr;
  17.   public
  18.    class operator  + (a,b: trec):trec;
  19.  end;
  20.  
  21.  procedure trec.initptr(v : int32);
  22.  begin
  23.   new(data);
  24.   data^ := v;
  25.  end;
  26.  
  27.  procedure trec.freeptr;
  28.  begin
  29.   dispose(data);
  30.  end;
  31.  
  32.  class operator trec.+ (a,b: trec):trec;
  33.  begin
  34.     result.data^ :=  a.data^ + b.data^;    
  35.  end;
  36.  
  37.  
  38. var
  39.  a,b,c : trec;
  40. begin
  41.  
  42.  a.initptr(10);
  43.  b.initptr(10);
  44.  c.initptr(0); // initililization
  45.  
  46.  c := a + b; // AV c.data is not initialized !?  
  47.  
  48.  writeln(c.data^);
  49.  a.freeptr; b.freeptr; c.freeptr;
  50.  readln;
  51. end.
  52.  
  53.  

cdbc

  • Hero Member
  • *****
  • Posts: 2251
    • http://www.cdbc.dk
Re: AV in operator overloading
« Reply #1 on: May 27, 2025, 09:38:55 am »
Hi
Code: Pascal  [Select][+][-]
  1.  class operator trec.+ (a,b: trec):trec;
  2.  begin
  3.     result.data^ :=  a.data^ + b.data^;    
  4.  end;
Why doesn't the 'Result' variable deserve to be initialized?!?
I dunno, maybe like this:
Code: Pascal  [Select][+][-]
  1. class operator trec.+ (a,b: trec):trec;
  2.  begin
  3.     result.initptr(a.data^ + b.data^);    
  4.  end;
And then:
Code: Pascal  [Select][+][-]
  1. var
  2.  a,b,c : trec;
  3. begin
  4.  
  5.  a.initptr(10);
  6.  b.initptr(10); // initililization
  7.  
  8.  c := a + b;
  9.  
  10.  writeln(c.data^);
  11.  a.freeptr; b.freeptr; c.freeptr;
  12.  readln;
  13. end.
Regards Benny
« Last Edit: May 27, 2025, 09:42:22 am by cdbc »
If it ain't broke, don't fix it ;)
PCLinuxOS(rolling release) 64bit -> KDE5 -> FPC 3.2.2 -> Lazarus 3.6 up until Jan 2024 from then on it's both above &: KDE5/QT5 -> FPC 3.3.1 -> Lazarus 4.99

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 11450
  • Debugger - SynEdit - and more
    • wiki
Re: AV in operator overloading
« Reply #2 on: May 27, 2025, 09:42:15 am »
result works like an "out param". It is not passed in.

So the result in your operator is not initialized, it is a new uninitialised local variable. And only when your operator returns, then it is assigned to c (overwriting the content of c).



This is even true for "operator :=".

This will assign (e.g. cast, or in whatever way create the data) to a local "result". And that local result is then copied over to the variable in the caller.



And yes, that means there will be extra memory movement.
« Last Edit: May 27, 2025, 09:44:18 am by Martin_fr »

cdbc

  • Hero Member
  • *****
  • Posts: 2251
    • http://www.cdbc.dk
Re: AV in operator overloading
« Reply #3 on: May 27, 2025, 09:44:17 am »
Hi
Edited my previous post...
Regards Benny
If it ain't broke, don't fix it ;)
PCLinuxOS(rolling release) 64bit -> KDE5 -> FPC 3.2.2 -> Lazarus 3.6 up until Jan 2024 from then on it's both above &: KDE5/QT5 -> FPC 3.3.1 -> Lazarus 4.99

cdbc

  • Hero Member
  • *****
  • Posts: 2251
    • http://www.cdbc.dk
Re: AV in operator overloading
« Reply #4 on: May 27, 2025, 09:50:02 am »
Hi Martin
Would that mean my example is wrong, he doesn't override the := operator?!?

edit: Just tested it with heaptrc and it works flawlessly in fpc 3.2.2
edit2: Here's my test program on linux:
Code: Pascal  [Select][+][-]
  1. program plusoperator;
  2.  
  3. {$mode objfpc}{$H+}
  4. {$modeswitch advancedrecords}
  5. uses cthreads,cwstring,sysutils;
  6.  
  7.  
  8. type
  9.  trec = record
  10.   public
  11.    data : pint32;
  12.   public
  13.    procedure initptr(v: int32);
  14.    procedure freeptr;
  15.   public
  16.    class operator  + (a,b: trec):trec;
  17.  end;
  18.  
  19.  procedure trec.initptr(v : int32);
  20.  begin
  21.   new(data);
  22.   data^ := v;
  23.  end;
  24.  
  25.  procedure trec.freeptr;
  26.  begin
  27.   dispose(data);
  28.  end;
  29.  
  30.  class operator trec.+ (a,b: trec):trec;
  31.  begin
  32.     result.initptr(a.data^ + b.data^);
  33.  end;
  34.  
  35.  
  36. var
  37.  a,b,c : trec;
  38. begin
  39.  
  40.  a.initptr(10);
  41.  b.initptr(10); // initialization
  42.  
  43.  c := a + b;
  44.  
  45.  writeln(c.data^);
  46.  a.freeptr; b.freeptr; c.freeptr;
  47.  readln;
  48. end.
Output = 20, No mem-leaks
Regards Benny
« Last Edit: May 27, 2025, 10:02:42 am by cdbc »
If it ain't broke, don't fix it ;)
PCLinuxOS(rolling release) 64bit -> KDE5 -> FPC 3.2.2 -> Lazarus 3.6 up until Jan 2024 from then on it's both above &: KDE5/QT5 -> FPC 3.3.1 -> Lazarus 4.99

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 11450
  • Debugger - SynEdit - and more
    • wiki
Re: AV in operator overloading
« Reply #5 on: May 27, 2025, 10:08:31 am »
Would that mean my example is wrong, he doesn't override the := operator?!?

Depends... Depends on what exactly you expect to be overridden.

":=" does an assignment. It also (matter of viewpoint) does a conversion if needed and if known how to.

This will NOT poke 8 bytes into the byte value.
Code: Pascal  [Select][+][-]
  1. SomeByteVal := SomeQWord;

The operator := does the conversion part, if you so chose to view it that way. And that expresses itself in the following
Code: Pascal  [Select][+][-]
  1. program Project1;
  2. {$Mode objfpc}
  3. type
  4.   TFoo = record end;
  5.  
  6. operator := (a: TFoo): TFoo;
  7. begin
  8. end;
  9. begin
  10. end.
returning Error: Impossible to overload assignment for equal types
« Last Edit: May 27, 2025, 10:14:49 am by Martin_fr »

fcu

  • Full Member
  • ***
  • Posts: 118
Re: AV in operator overloading
« Reply #6 on: May 27, 2025, 10:37:03 am »
thanks , i thought it may works like c++
Code: C  [Select][+][-]
  1. struct sData{
  2. public:
  3.   sData(int v){ data = new int; *data = v;}
  4.   sData& operator  + (sData d){
  5.      *data += *d.data;
  6.     return *this;
  7.   }
  8. public:
  9.   int * data;
  10. };
  11.  

Thaddy

  • Hero Member
  • *****
  • Posts: 17405
  • Ceterum censeo Trumpum esse delendum (Tnx Charlie)
Re: AV in operator overloading
« Reply #7 on: May 27, 2025, 12:52:56 pm »
It essentially works like C++ but you did the new part wrong.
Due to censorship, I changed this to "Nelly the Elephant". Keeps the message clear.

PascalDragon

  • Hero Member
  • *****
  • Posts: 6035
  • Compiler Developer
Re: AV in operator overloading
« Reply #8 on: May 27, 2025, 10:07:41 pm »
thanks , i thought it may works like c++
Code: C  [Select][+][-]
  1. struct sData{
  2. public:
  3.   sData(int v){ data = new int; *data = v;}
  4.   sData& operator  + (sData d){
  5.      *data += *d.data;
  6.     return *this;
  7.   }
  8. public:
  9.   int * data;
  10. };
  11.  

Note the sData& in your C++ code. That's a reference. A return value of a function (or operator) in Pascal is never a reference (ignoring some implementation details situations here which might have the appearance that it does, but from a language point of view it isn't).

result works like an "out param". It is not passed in.

So the result in your operator is not initialized, it is a new uninitialised local variable. And only when your operator returns, then it is assigned to c (overwriting the content of c).



This is even true for "operator :=".

This will assign (e.g. cast, or in whatever way create the data) to a local "result". And that local result is then copied over to the variable in the caller.

It's not quite right. Depending on the record it might indeed work like an out-parameter (or more precisely a var-parameter) and then the code would work; e.g. a record that contains a managed type will be passed like this, while others will use a copy.

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 11450
  • Debugger - SynEdit - and more
    • wiki
Re: AV in operator overloading
« Reply #9 on: May 27, 2025, 10:28:41 pm »
It's not quite right. Depending on the record it might indeed work like an out-parameter (or more precisely a var-parameter) and then the code would work; e.g. a record that contains a managed type will be passed like this, while others will use a copy.

Are you sure that isn't misleading too?
Or I am overlooking something, and it might be considered a severe side effect....

Afaik, implementation detail, some result param are var param. But, they always get a temp var passed from the caller. So you don't have a reference to the callers var.
Which from a users point of view makes it an out param.

Otherwise, If I am assigning the returned result to a global var, that global vars content could change, before the result is returned. And that afaik it should not (actually must not?)



At least below, the record is not behaving like a var param:
Code: Pascal  [Select][+][-]
  1. program Project1;
  2. {$Mode objfpc}
  3. type  TFoo = record s, s2,s3,s4,s5: ansistring; end;
  4. var   a: tfoo;
  5.  
  6. function x: tfoo;
  7. begin
  8.   Result.s := StringOfChar('a', 10+Random(2));
  9.   writeln( a.s); // Does write bbbb
  10. end;
  11.  
  12. begin
  13.   a.s := StringOfChar('b', 2+Random(2));
  14.   a := x; // a is not passed as var param
  15. end.
  16.  

Even though, implementation wise it is, but with a temp var.

Of course there is a case were it can be observed. If peeking at uninitialized values. When calling "a:=x;" twice, the 2nd call will see the returned value of the 1st call. 

PascalDragon

  • Hero Member
  • *****
  • Posts: 6035
  • Compiler Developer
Re: AV in operator overloading
« Reply #10 on: May 27, 2025, 10:37:00 pm »
It's not quite right. Depending on the record it might indeed work like an out-parameter (or more precisely a var-parameter) and then the code would work; e.g. a record that contains a managed type will be passed like this, while others will use a copy.

Are you sure that isn't misleading too?
Or I am overlooking something, and it might be considered a severe side effect....

Afaik, implementation detail, some result param are var param. But, they always get a temp var passed from the caller. So you don't have a reference to the callers var.

It's indeed very much an implementation detail, but it nevertheless does not change that the compiler does this. And even if the compiler currently does not optimize it to pass the destination variable directly it might or could do so in the future.
 
Which from a users point of view makes it an out param.

But only as long as they don't call the function multiple times in a row, because then the compiler will reuse the temporary variable... ;)

 

TinyPortal © 2005-2018