I have a piece of code that looks like this. I works fine, but I do not trust it. Is this code fine or unsafe?
When I do 'poly(1) = poly(0)' when/how/who/what allocates memory for the 'points' array of 'poly(1)'?
type sgl2d
dim as single x, y
end type
type polygon
redim as sgl2d points(any)
declare destructor()
declare sub init()
end type
destructor polygon()
print "destructor polygon() @ "; hex(@this)
print "points @ "; hex(@points(0))
print "bounds:"; lbound(points); ubound(points)
print
erase(points)
end destructor
sub polygon.init()
redim points(0 to 2)
points(0).x = 123 : points(0).y = 456
end sub
dim as polygon poly(0 to 1)
poly(0).init()
poly(1) = poly(0) '<--- Why does this work? How is memory allocated for points?
poly(1).destructor()
poly(1) = poly(0) '<-- Let's try again
print poly(1).points(0).x, poly(1).points(0).y
print
print "Program exit"
print
The code is safe, but very sploppy coding ...
What I mean above is:
you always omit the "This" specifier before the types member access, which
makes code harder to read, too.
type sgl2d
dim as single x, y
end type
type polygon
As sgl2d points(any)
Declare destructor()
Declare sub init()
end type
destructor polygon()
Print "destructor polygon() @ "; hex(@This)
Print "points @ "; hex(@This.points(0))
Print "bounds:"; lbound(This.points); ubound(This.points)
Print
Erase(points)
end destructor
sub polygon.init()
ReDim This.points(0 to 2) ' <--- memory allocated for points
This.points(0).x = 123
This.points(0).y = 456
End sub
dim as polygon poly(0 to 1)
poly(0).init() ' below works because of this!!!
poly(1) = poly(0) '<--- Why does this work? How is memory allocated for points?
poly(1).destructor()
poly(1) = poly(0) '<-- Let's try again
print poly(1).points(0).x, poly(1).points(0).y
print
print "Program exit"
print
sleep
There is one 'This' missing ! :-) Erase(This.points)
(but I do not criticize your remark: I, too, always precise 'This.' in the member procedures)
@badidea,
(more seriously)
For UDT containing a dynamic array as a member field, the implicit Let operator:
- Size the dynamic array of the left-hand operand as that of the right-hand operand ([re]sizing or erasing).
- Then copy all elements (if sized).
Note: Obviously if you define your own overload Let operator, it's up to you to code all this in your own operator's body.
..... Variable-length data
In FreeBASIC, Type data structures must ultimately be fixed-size, such that the compiler knows how much memory to allocate for objects of that Type. Nevertheless, Types may contain variable-length (dynamic) string or array data members. However, the string's/array's data will not be embedded in the Type directly. Instead, the Type will only contain a String/array descriptor structure, which FreeBASIC uses behind the scenes to manage the variable-length string/array data. For sizing the structure of the array descriptor in the Type, a variable-length (dynamic) array data member must be always declared by using Any(S) in place of the array bounds, in order to fix the amount of dimensions based on the number of Anys specified. Variable-length array fields are considered as pseudo-objects when they are declared in a Type, just like variable-length strings (the implicit copy constructor and the implicit let operator themselves support [re]sizing and copying such arrays, or their erasing).
.....