constructor called twice: string reference not preserved with static sub

General FreeBASIC programming questions.
Munair
Posts: 1286
Joined: Oct 19, 2017 15:00
Location: Netherlands
Contact:

Re: constructor called twice: string reference not preserved with static sub

Post by Munair »

In my project the pointer assignment already seems to do the trick:

Code: Select all

operator TForm1.let (tt as TForm1)
  ' FileType = tt.FileType
  thisp_ = @this
end operator
Now the program does not crash when recreating the object.
fxm
Moderator
Posts: 12081
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: constructor called twice: string reference not preserved with static sub

Post by fxm »

In the specific context of your program, yes.
Munair
Posts: 1286
Joined: Oct 19, 2017 15:00
Location: Netherlands
Contact:

Re: constructor called twice: string reference not preserved with static sub

Post by Munair »

Why was this entire topic deleted? fxm just added a useful post and I found it very helpful.

viewtopic.php?p=254109#p254109
fxm
Moderator
Posts: 12081
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: constructor called twice: string reference not preserved with static sub

Post by fxm »

The topic (viewtopic.php?f=17&t=20434) is not deleted.
I only deleted my last today post which was in fact erroneous.
Munair
Posts: 1286
Joined: Oct 19, 2017 15:00
Location: Netherlands
Contact:

Re: constructor called twice: string reference not preserved with static sub

Post by Munair »

fxm wrote:The topic (viewtopic.php?f=17&t=20434) is not deleted.
I only deleted my last today post which was in fact erroneous.
OK, thanks.
Munair
Posts: 1286
Joined: Oct 19, 2017 15:00
Location: Netherlands
Contact:

Re: constructor called twice: string reference not preserved with static sub

Post by Munair »

One situation I can think of that reassigning an object can be useful, is when using static objects in functions to return them by reference:

Code: Select all

type TExample extends object
	text as string
	declare constructor()
end type

constructor TExample()
end constructor

function Test(number as integer) byref as TExample
	static example as TExample
	
	' clear object (uncomment to see difference)
	' example = TExample
	
	if number > 0 then
		example.text = "positive"
	elseif number < 0 then
		example.text = "negative"
	end if
	
	return example
end function

dim example as TExample

example = Test(3)
print example.text
example = Test(-2)
print example.text
example = Test(0)
print example.text
end
Munair
Posts: 1286
Joined: Oct 19, 2017 15:00
Location: Netherlands
Contact:

Re: constructor called twice: string reference not preserved with static sub

Post by Munair »

As a final thought, here is what I believe would be a great improvement. Upon definition a NULL object should be created because it is not known what should happen to an object with multiple constructors. What constructor must be invoked? Should the default constructor be invoked regardless?

Currently, the default constructor is ignored if another constructor is called. Preferably, when the object is actually instantiated (using a custom constructor), the default constructor is always called first. Even better, keywords like "inherited" may indicate if that should happen.

Code: Select all

type TExample extends object
	text1 as string
	text2 as string
	declare constructor()
	declare constructor(value as string)
end type

constructor TExample()
	text1 = "positive"
end constructor

constructor TExample(value as string)
	inherited 'pseudo code invokes default constructor
	text2 = value
end constructor

dim example as TExample = TExample("negative")

print example.text1
print example.text2

end
Perhaps a thought for a future release when full class support will be implemented.
fxm
Moderator
Posts: 12081
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: constructor called twice: string reference not preserved with static sub

Post by fxm »

1)
For me, defining a null object (including for UDT) may correspond to the result of a default construction:
Dim null As datatype

2)

Code: Select all

type TExample extends object
   text1 as string
   text2 as string
   declare constructor()
   declare constructor(value as string)
end type

constructor TExample()
   text1 = "positive"
end constructor

constructor TExample(value as string)
   constructor() 'to be always used at the first line 'inherited 'pseudo code invokes default constructor
   text2 = value
end constructor

dim example as TExample = TExample("negative")

print example.text1
print example.text2

sleep
  • See documentation at CONSTRUCTOR:
    Chaining together constructors of a same type is allowed by using the keyword Constructor(parameters) at the top of constructor. It prevents the compiler from emitting field initialization code (instead, it relies on the chained constructor to initialize everything).
sancho3
Posts: 358
Joined: Sep 30, 2017 3:22

Re: constructor called twice: string reference not preserved with static sub

Post by sancho3 »

@fxm:
I think I get what you are saying.
Because thisp is set to @this in the constructor, it is pointing to the newly created temporary type and that is immediately destroyed.
In your example the UDT fields are copied from the temp type (a shallow copy)?

In this example the temporary type is created but the only reason p->x and p->y show 12,13 values is because they are left in memory. That memory can be reclaimed at any point. Is that correct?

Code: Select all

Type test 
	As Integer x, y
	Declare Destructor
End Type
Destructor test() 
	? "Destroy: "; Hex(@this)
End Destructor

Dim As test Ptr p = @(type<test>(12,13)) 

? Hex(p), p->x, p->y 

Sleep 

Is there a name for values left in memory like this example? If not, I propose "dangling values".
fxm
Moderator
Posts: 12081
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: constructor called twice: string reference not preserved with static sub

Post by fxm »

Yes for all (one calls this a "dangling pointer").

I added a string field to your example to demonstrate that the string character data are well deallocated (and string descriptor field cleared in the data of the temporary type):

Code: Select all

Type test
   As Integer x, y
   As String s
   Declare Destructor
   Declare Constructor ()
   Declare Constructor (Byval x As Integer, Byval y As Integer, Byref s As String)
End Type
Destructor test()
   ? "Destroy: "; Hex(@this)
End Destructor

Constructor test ()
End Constructor

Constructor test (Byval x As Integer, Byval y As Integer, Byref s As String)
  This.x = x
  This.y = y
  This.s = s
End Constructor

Dim As test Ptr p = @test(12, 13, "string")

? Hex(p), p->x, p->y, "'" & p->s & "'"

Sleep

Code: Select all

Destroy: 19FE8C
19FE8C         12            13           ''
Munair
Posts: 1286
Joined: Oct 19, 2017 15:00
Location: Netherlands
Contact:

Re: constructor called twice: string reference not preserved with static sub

Post by Munair »

Adding a static pointer to sancho3's example, we can see that "re-instantiating" the object to clear the data actually creates a temporary instance, as fxm explained. The data are then copied to the memory block of the first instance. However, a static pointer will keep pointing to the memory block of the temporary instance:

Code: Select all

type test
   x as integer
   y as integer
   s as string
   static pthis as test ptr
   declare destructor()
   declare constructor()
   declare constructor(byval x as integer, byval y as integer, byref s as string)
end type

constructor test()
	pthis = @this
	print "assigned static pointer in default constructor:"; hex(pthis)
end constructor

constructor test(byval x as integer, byval y as integer, byref s as string)
	constructor()
  this.x = x
  this.y = y
  this.s = s
end constructor

destructor test()
   print "destroy: "; hex(@this)
end destructor

dim test.pthis as test ptr

print "instantiating: t as test = test(12, 13, 'string')"
dim t as test = test(12, 13, "string")
print "member values:"
print t.x, t.y, "'" & t.s & "'"
print "pointer:"; hex(@t)
print "static pointer:"; hex(t.pthis)
print
print "instantiating: t=test:"
t = test()
print "member values:"
print t.x, t.y, "'" & t.s & "'"
print "pointer:"; hex(@t)
print "static pointer:"; hex(t.pthis)
end
Would it not be more logical and efficient to simply destroy the first instance and then create a new one? (That is actually what I expected.) A static pointer will then also point to the correct memory location.
Munair
Posts: 1286
Joined: Oct 19, 2017 15:00
Location: Netherlands
Contact:

Re: constructor called twice: string reference not preserved with static sub

Post by Munair »

Adding a simple LET operator to update the static pointer will prevent the "new" instance from being cleared:

Code: Select all

type test
   x as integer
   y as integer
   s as string
   static pthis as test ptr
   declare destructor()
   declare constructor()
   declare constructor(byval x as integer, byval y as integer, byref s as string)
   declare operator let(tt as test)
end type

constructor test()
	pthis = @this
	print "assigned static pointer in default constructor:"; hex(pthis)
end constructor

constructor test(byval x as integer, byval y as integer, byref s as string)
	constructor()
  this.x = x
  this.y = y
  this.s = s
end constructor

destructor test()
   print "destroy: "; hex(@this)
end destructor

operator test.let(tt as test)
	pthis = @this
	print "assigned static pointer in operator:"; hex(pthis)
end operator

dim test.pthis as test ptr

print "instantiating: t as test = test(12, 13, 'string')"
dim t as test = test(12, 13, "string")
print "member values:"
print t.x, t.y, "'" & t.s & "'"
print "pointer:"; hex(@t)
print "static pointer:"; hex(t.pthis)
print
print "instantiating: t=test:"
t = test()
print "member values:"
print t.x, t.y, "'" & t.s & "'"
print "pointer:"; hex(@t)
print "static pointer:"; hex(t.pthis)
end
Last edited by Munair on Nov 04, 2018 12:33, edited 1 time in total.
fxm
Moderator
Posts: 12081
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: constructor called twice: string reference not preserved with static sub

Post by fxm »

More generally, for a Type containing at least a pointer as member (and therefore potentially dynamic data), user must always ask himself if the implicit copy-constructor, implicit assignment-operator and implicit destructor are sufficient or must be redefined.
Munair
Posts: 1286
Joined: Oct 19, 2017 15:00
Location: Netherlands
Contact:

Re: constructor called twice: string reference not preserved with static sub

Post by Munair »

fxm wrote:More generally, for a Type containing at least a pointer as member (and therefore potentially dynamic data), user must always ask himself if the implicit copy-constructor, implicit assignment-operator and implicit destructor are sufficient or must be redefined.
That's not for a Type. That's for an object, which also (still) uses the Type keyword. Hopefully, one day with full class implementation (if that is ever to happen), the difference and behavior between the two will be more logical. Currently FreeBasic appears to be in sort of an in-between state. The examples above demonstrate unpreferred behavior with objects IMHO, which may or may not be the result of the TYPE legacy. I can't tell.
Munair
Posts: 1286
Joined: Oct 19, 2017 15:00
Location: Netherlands
Contact:

Re: constructor called twice: string reference not preserved with static sub

Post by Munair »

I made an error in the last example containing the OPERATOR LET construct. The operator correctly forces the static pointer back to the initial instance (which is what we want to avoid a segmentation fault).
Post Reply