Calling byval class

General FreeBASIC programming questions.
Post Reply
aloberoger
Posts: 507
Joined: Jan 13, 2009 19:23

Calling byval class

Post by aloberoger »

I am confuse, In this example we notice that in DET function the destructor is called but th object is not destroyed Why?

Code: Select all

#Include Once "windows.bi"
#Include Once "vbcompat.bi"
 

#Include Once "crt.bi"


Type TMatrix
	Private:
	  Arr(1 To 2, 1 To 2) As Double
	Public:
	   Declare Constructor
	   Declare Destructor Cdecl
	   Declare Function at(row As Integer, col As Integer) ByRef As Double
End Type


Constructor  TMatrix()  
Print "in Constructor"
End Constructor

Destructor TMatrix()   
  Erase Arr
  Print "in Destructor"
End Destructor

 Function TMatrix.at(irow As Integer,icol As Integer) ByRef As Double
 	 If irow<1 Or irow>2 _
    	Or icol<1 Or icol>2 Then  
    	Messagebox NULL , "Les indices sont en dehors de la plage (" & irow & ";" & icol & ")" ,"erreur dans Matrix.at",MB_ICONERROR
    	Exit Function
    EndIf
     Return Arr(irow,icol)
 End Function


Function DET(ByVal m As TMatrix) As Double
	Print "in DET"
	Return m.at(1,1)*m.at(2,2) - M.at(1,2)*m.at(2,1)    ' the destructor is called but m is still valid
End Function


Function DET2(ByRef m As TMatrix) As Double
	Print "in DET"
	Return m.at(1,1)*m.at(2,2) - M.at(1,2)*m.at(2,1)     ' no destructor is called but m is still valid  ok
End Function

 
  Dim M1 As TMatrix  
 
  M1.at(1,1)=1.00  : M1.at(1,2)=2.00  
  M1.at(2,1)=3.00 : M1.at(2,2)=5.00 

 
  For i As Integer=1 To 2
  	  For j As Integer=1 To 2
  	     Print M1.at(i,j);
  	  Next j
  	  Print
  Next
 
 Print " det(m)= " & DET(m1)
 
 Print " after byval call "
 
 For i As Integer=1 To 2
  	  For j As Integer=1 To 2
  	     Print M1.at(i,j);
  	  Next j
  	  Print
  Next
 
 Print
 Print " det2(m)= " & DET2(m1)
 
 Print " after byref call "
 
 For i As Integer=1 To 2
  	  For j As Integer=1 To 2
  	     Print M1.at(i,j);
  	  Next j
  	  Print
  Next
 
 Print
  
  Sleep
fxm
Moderator
Posts: 12107
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Calling byval class

Post by fxm »

When you pass to 'det2()' the TMatrix instance 'M1' by value, in fact a copy of 'M1' is passed to the procedure.
It is this copy which is destroyed (with the array erased) at the end of the procedure, but not 'M1' fortunately!

You do not see the construction of this copy, because in this case, the copy-constructor is called.

Added code to visualize the different constructions and destructions:

Code: Select all

#Include Once "windows.bi"
#Include Once "vbcompat.bi"
 
#Include Once "crt.bi"

Type TMatrix
   Private:
      Arr(1 To 2, 1 To 2) As Double
   Public:
      Declare Constructor
      Declare Constructor (byref m As TMatrix)
      Declare Destructor Cdecl
      Declare Function at(row As Integer, col As Integer) ByRef As Double
End Type

Constructor  TMatrix() 
   Print "in Constructor", @This
End Constructor

Constructor  TMatrix(byref m As TMatrix) 
   Print "in Copy-Constructor", @This
   This = m
End Constructor

Destructor TMatrix()   
   Erase Arr
   Print "in Destructor",, @This
End Destructor

Function TMatrix.at(irow As Integer,icol As Integer) ByRef As Double
   If irow<1 Or irow>2 _
      Or icol<1 Or icol>2 Then 
      Messagebox NULL , "Les indices sont en dehors de la plage (" & irow & ";" & icol & ")" ,"erreur dans Matrix.at",MB_ICONERROR
      Exit Function
   EndIf
   Return Arr(irow,icol)
End Function

Function DET(ByVal m As TMatrix) As Double
   Print "in DET"
   Return m.at(1,1)*m.at(2,2) - M.at(1,2)*m.at(2,1)    ' the destructor is called but m is still valid
End Function

Function DET2(ByRef m As TMatrix) As Double
   Print "in DET"
   Return m.at(1,1)*m.at(2,2) - M.at(1,2)*m.at(2,1)     ' no destructor is called but m is still valid  ok
End Function


Scope
    
   Dim M1 As TMatrix
 
   M1.at(1,1)=1.00  : M1.at(1,2)=2.00 
   M1.at(2,1)=3.00 : M1.at(2,2)=5.00

 
   For i As Integer=1 To 2
      For j As Integer=1 To 2
         Print M1.at(i,j);
      Next j
       Print
   Next
 
   Print
   Print " det(m)= " & DET(m1)
 
   Print " after byval call "
 
   For i As Integer=1 To 2
      For j As Integer=1 To 2
         Print M1.at(i,j);
      Next j
      Print
   Next
 
   Print
   Print " det2(m)= " & DET2(m1)
 
   Print " after byref call "
 
   For i As Integer=1 To 2
      For j As Integer=1 To 2
         Print M1.at(i,j);
      Next j
      Print
   Next
 
   Print
 
End Scope
 
Sleep

Code: Select all

in Constructor              1703548
 1 2
 3 5

in Copy-Constructor         1703516
in DET
 det(m)= -1
in Destructor               1703516
 after byval call
 1 2
 3 5

in DET
 det2(m)= -1
 after byref call
 1 2
 3 5

in Destructor               1703548
aloberoger
Posts: 507
Joined: Jan 13, 2009 19:23

Re: Calling byval class

Post by aloberoger »

ok
do you want to say that we have to call classes and return classes with byval specification?
fxm
Moderator
Posts: 12107
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Calling byval class

Post by fxm »

No, no systematic rule.
The most common is to pass type instances by reference and return them by value.
aloberoger
Posts: 507
Joined: Jan 13, 2009 19:23

Re: Calling byval class

Post by aloberoger »

The most common is to pass type instances by reference and return them by value.
urprisingly, I'm going to review the work I had to do with the synthesis that I thought we had to return class references
fxm
Moderator
Posts: 12107
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Calling byval class

Post by fxm »

When you do not specify the passing mode of parameters (without 'Byval' and 'Byref' keywords), they are by default passed by values, except for string and UDT instances which are passed by references, and for arrays which are always passed by references.
Post Reply