If eax = *p, then FreeMemory(*p) before ProcedureReturn?

Just starting out? Need help? Post your questions and find answers here.
User avatar
Demivec
Addict
Addict
Posts: 4270
Joined: Mon Jul 25, 2005 3:51 pm
Location: Utah, USA

Re: If eax = *p, then FreeMemory(*p) before ProcedureReturn?

Post by Demivec »

@skywalk: I'm not sure what you are trying to accomplish with such a small static array with only 2 elements. This will surely cause you problems with nested calls.

Using the method I posted with an array of only 10 elements will allow calls like:

Code: Select all

cSum2(cSum2(cSum2(cSum2(cSum2(cSum2(cSum2(cSum2(A,B),B),B),B)B),B),B),cSum2(A,cSum2(A,B)))
To preserve the result that is returned just copy the structure to a structured variable like so:

Code: Select all

;with variable
C.csi
CopyStructure(cSum2(A,B), C, csi)
;or with pointers
*D.csi
CopyStructure(cSum2(csum2(B,A), B), *D, csi)
wilbert tried a variation of my approach but his required a global array of structured variables and also a search for unused variables each time the procedure was called. My approach simply used the next index.


I've used the approach that you demonstrated first where you passed the pointer in. This requires some acrobatic work to perform nested calls by using lots of single calls. The method that allocates a new structure each time requires you to free it when you're done with it. As you know that method doesn't work with nested calls without memory leaks.

Since your goal is to make nested calls and to keep the parameter count down I think the static array method would be a good choice. You only need to decide on how many indices to set aside to handle the depth of nesting that you expect. As you can see from my example above that can probably be kept under 10.


It would be great if this process was automated and made native. In the mean time it is not very difficult to implement it this way. If thread safety is needed it does get messier.
User avatar
skywalk
Addict
Addict
Posts: 4219
Joined: Wed Dec 23, 2009 10:14 pm
Location: Boston, MA

Re: If eax = *p, then FreeMemory(*p) before ProcedureReturn?

Post by skywalk »

Hi Demivec,
Yeah it was late and I was trying lots of variations. :oops:
I will ponder this some more, but like you said, the 3 parameter approach is cleaner but ugly.

Thanks wilbert and xorc1zt for your suggestions.
The nice thing about standards is there are so many to choose from. ~ Andrew Tanenbaum
Trond
Always Here
Always Here
Posts: 7446
Joined: Mon Sep 22, 2003 6:45 pm
Location: Norway

Re: If eax = *p, then FreeMemory(*p) before ProcedureReturn?

Post by Trond »

Be careful so you free all allocated memory. In your example, you allocate memory for *C, then make an assignment to it (*C = cSum2(A,B)). So the memory you allocated is lost.

I think you should go with #3 or something like this:

Code: Select all


Global SRefCounted_ObjectCounter ; Only for debugging
Structure SRefCounted ; Extend from this to allow refcounting
  RefCount.i
EndStructure

Structure cri Extends SRefCounted ; Define complex rectangular(real/imag) or polar(mag/ang)
  r.d   ; real or mag
  i.d   ; imag or ang
EndStructure

; Create support procedures for a new refcounted type
Macro New_Refcounted(Type)
  Procedure New#Type()
    SRefCounted_ObjectCounter + 1
    *M.SRefCounted =  AllocateMemory(SizeOf(Type))
    Debug "allocate " + Str(*M)
    *M\RefCount = 1
    ProcedureReturn *M
  EndProcedure
EndMacro

Procedure Get(*M.SRefCounted)
  If *M And *M\RefCount > 0
    *M\RefCount + 1
  EndIf
EndProcedure

Procedure Release(*M.SRefCounted)
  If *M
    If *M\RefCount
      If *M\RefCount = 1
        Debug "free " + Str(*M)
        SRefCounted_ObjectCounter - 1
        FreeMemory(*M)
      Else
        *M\RefCount - 1
      EndIf
    EndIf
  EndIf
EndProcedure

New_Refcounted(cri)


Procedure.i cSum4(*x.cri, *y.cri)
  ; Return complex sum of 2 complex numbers
  ; Returns Pointer to Structured memory.
  *r.cri = NewCri()
  *r\r = *x\r + *y\r
  *r\i = *x\i + *y\i
  Release(*x)
  Release(*y)
  ProcedureReturn *r
EndProcedure

;- Example

Global a.cri, b.cri, *c.cri

A\r  = 1: A\i  = 1
B\r  = 2: B\i  = 2


*C = cSum4(A, cSum4(A,B))
Debug "[1+1i] + ([1+1i] + [2+2i]) = " + StrD(*C\r,1) + " + " +StrD(*C\i,1) + "i"
Release(*c)

Debug SRefCounted_ObjectCounter ; Shouldn't be rising, else you know you're leaking memory. 0 is fine.
In addition to pointers, normal variables (not pointers) can also be passed as parameters. Because when the refcount field is 0, the variable is seen as "static", and will not be freed by Release().
User avatar
idle
Always Here
Always Here
Posts: 5914
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: If eax = *p, then FreeMemory(*p) before ProcedureReturn?

Post by idle »

is there anything wrong with this?

Code: Select all

Structure cri 
  r.d   ; real or mag
  i.d   ; imag or ang
EndStructure

Procedure.i cSum4(*x.cri, *y.cri)
  Static r.cri 
  r\r = *x\r + *y\r
  r\i = *x\i + *y\i
  ProcedureReturn @r
EndProcedure
;- Example

Global a.cri, b.cri, *c.cri

A\r  = 1: A\i  = 1
B\r  = 2: B\i  = 2

*C = cSum4(A, cSum4(A,B))
Debug "[1+1i] + ([1+1i] + [2+2i]) = " + StrD(*C\r,1) + " + " +StrD(*C\i,1) + "i"
Windows 11, Manjaro, Raspberry Pi OS
Image
User avatar
STARGÅTE
Addict
Addict
Posts: 2235
Joined: Thu Jan 10, 2008 1:30 pm
Location: Germany, Glienicke
Contact:

Re: If eax = *p, then FreeMemory(*p) before ProcedureReturn?

Post by STARGÅTE »

is there anything wrong with this?
yes ^^

Code: Select all

A\r  = 0: A\i  = 1
B\r  = 1: B\i  = 0
*C = cSum4(cSum4(A,A), cSum4(B,B))
Debug StrD(*C\r,1) + " + " +StrD(*C\i,1) + "i"
[(1+0i)+(1+0i)] + [(0+1i)+(0+1i)] = 2+2i but you get 0+4i , because A+A overwrite the result B+B (parameter evaluate from right to left), so you eval A+A+A+A

here some trick from me, to use 2 floats in one Quad to return it from a procedure:
http://www.purebasic.fr/german/viewtopi ... =8&t=24674
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Lizard - Script language for symbolic calculations and moreTypeface - Sprite-based font include/module
User avatar
STARGÅTE
Addict
Addict
Posts: 2235
Joined: Thu Jan 10, 2008 1:30 pm
Location: Germany, Glienicke
Contact:

Re: If eax = *p, then FreeMemory(*p) before ProcedureReturn?

Post by STARGÅTE »

here my code to work with complex values:

without allocatememory, global, staitc ... only two Floats in one Quad !

Code: Select all


Structure Complex
	StructureUnion
		Quad.q : Float.f[2]
	EndStructureUnion
EndStructure

Procedure.q Complex(Re.f, Im.f)
	Protected Object.Complex
	Object\Float[0] = Re : Object\Float[1] = Im
	ProcedureReturn Object\Quad
EndProcedure

Procedure.q ComplexPlus(A.q, B.q)
	Protected *A.Complex = @A, *B.Complex = @B
	ProcedureReturn Complex(*A\Float[0]+*B\Float[0], *A\Float[1]+*B\Float[1])
EndProcedure

Procedure.q ComplexTimes(A.q, B.q)
	Protected *A.Complex = @A, *B.Complex = @B
	ProcedureReturn Complex(*A\Float[0]**B\Float[0]+*A\Float[1]**B\Float[1], *A\Float[0]**B\Float[1]+*A\Float[1]**B\Float[0])
EndProcedure

Procedure.f ComplexAbs(A.q)
	Protected *A.Complex = @A
	ProcedureReturn Sqr(*A\Float[0]**A\Float[0]+*A\Float[1]**A\Float[1])
EndProcedure

Procedure.s ComplexStr(A.q)
	Protected *A.Complex = @A
	ProcedureReturn RTrim(StrF(*A\Float[0]),"0")+" + "+RTrim(StrF(*A\Float[1]),"0")+" i"
EndProcedure

A.q = Complex(0, 1)
B.q = Complex(1, 0)

Debug ComplexStr(ComplexPlus(A, B))
Debug ComplexStr(ComplexTimes(A, A))

Debug ComplexStr(ComplexPlus(ComplexPlus(A, A), ComplexPlus(B, B)))

Debug ComplexAbs(Complex(1, 1))
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Lizard - Script language for symbolic calculations and moreTypeface - Sprite-based font include/module
Post Reply