The old one was moving pointers. Now I am trying to move objects that contain a handler with the pointer.
So in the old API I had:
proc len*(vsmap:ptr VSMap, key:cstring):int =
while in the new API:
type
VSMapObj* = object
handle*:ptr VSMap
proc `=destroy`*(self: VSMapObj) =
if not self.handle.isNil:
api.handle.freeMap(self.handle) # this is from the C API
...
proc len*(vsmap:VSMapObj; key:string):int =
Now I am facing some memory issues, probably due to my bad understanding of the topic. When I compile ex06_adding.nim it works fine, but then after the execution it tries to destroy an VSCoreObj instance which uses the same approach as above. I get the error:
false
200 frames written to 'demo.y4m'
[INFO] destroying VSCoreObj instance
Traceback (most recent call last)
/home/jose/src/nimlang/vs.nim/src/lib/libcore.nim(17) ex06_adding
/home/jose/src/nimlang/vs.nim/src/lib/libcore.nim(21) =destroy
SIGSEGV: Illegal storage access. (Attempt to read from nil?)
Error: execution of an external program failed: '/home/jose/src/nimlang/vs.nim/tests/ex06_adding'
The issue is in this line, but I don't get it. One VSCoreObj instance is needed and I create it here for the whole execution. It looks like =destroy' is called only once since the `[INFO] destroying VSCoreObj instance line only appears once.
Do you see any obvious error?
At the bare minimum add:
proc `=copy`*(dest: var VSMapObj; src: VSMapObj) {.error.}
Thanks Araq.
Trying what you say I get:
/home/jose/src/nimlang/vs.nim/src/lib/sugarized/operations.nim(68, 15) Error: '=dup' is not available for type <VSMapObj>, which is inferred from unavailable '=copy'; requires a copy because it's not the last read of 'clip1'; try to make clip1 a 'sink' parameter; routine: +
It is complaining about the following function:
proc `+`*(clip1:VSMapObj, clip2:VSMapObj):VSMapObj =
## Adds two clips
var tmp = @[clip1, clip2] # <----
let clips = gen_clips(tmp)
splice(clips, mismatch=0.some)
I am not familiar with the move semantics.
I did:
proc `+`*(clip1:sink VSMapObj, clip2:sink VSMapObj):VSMapObj =
without success:
/home/jose/src/nimlang/vs.nim/tests/ex06_adding.nim(6, 11) Error: '=dup' is not available for type <VSMapObj>, which is inferred from unavailable '=copy'; requires a copy because it's not the last read of 'c1'; routine: ex06_adding
Regarding option 2, I understand you mean something like:
type
VSMapRef = ref VSMapObj
Don't forget to set your handle to nil after freeing it to avoid double frees!
That is not the best practice anymore and cannot even be done in a non-var-T destructor. ;-) The compiler does the set-to-nil for you, or rather the system was designed for it to not be necessary as the destructor does not run again on an already destroyed object.
I keep on trying to understand what goes on with the move semantics.
I am trying the following:
import vs
proc main =
let c1 = source("2sec.mkv") # OK
discard c1.saveY4M("demo.y4m") # OK
echo c1 # OK
`=destroy`(c1) # shows 'destroying VSMapObj'
echo c1.handle.isNil # shows 'false'
# shows 'destroying VSMapObj' again
main()
It saves the video file and echos c1.
Then I try to manually destroy c1.
Bearing in mind that:
type
VSMapObj* = object
handle*:ptr VSMap
proc `=destroy`*(self: VSMapObj) =
if not self.handle.isNil:
echo "destroying VSMapObj"
api.handle.freeMap(self.handle)
The output is:
destroying VSMapObj
VSMap: 1 item(s)
(key: "clip", typ: ptvideonode, n: 1, idx: 0)
destroying VSMapObj
false
destroying VSMapObj
Traceback (most recent call last)
/home/jose/src/nimlang/vs.nim/tests/ex08_mm1.nim(11) ex08_mm1
/home/jose/src/nimlang/vs.nim/src/lib/libvsmap.nim(31) main
/home/jose/src/nimlang/vs.nim/src/lib/libvsmap.nim(34) =destroy
SIGSEGV: Illegal storage access. (Attempt to read from nil?)
Error: execution of an external program failed: '/home/jose/src/nimlang/vs.nim/tests/ex08_mm1'
I would expect c1.handle.isNil being nil, wouldn't it?
The generated code is:
var
c1
:tmpD
:tmpD_1
:tmpD_2
:tmpD_3
:tmpD_4
try:
c1 = source("2sec.mkv", none(int), none(int),
:tmpD = none_1(string)
:tmpD, none(int), none(int), none(int),
:tmpD_1 = none_1(string)
:tmpD_1, none(int), none(int), none(int),
:tmpD_2 = none_1(string)
:tmpD_2, none(int), none(int))
discard saveY4M(c1, "demo.y4m")
echo [
:tmpD_3 = `$`(c1)
:tmpD_3]
`=destroy`(c1)
echo [
:tmpD_4 = `$`(isNil(c1.handle))
:tmpD_4]
finally:
`=destroy`(:tmpD_4)
`=destroy`(:tmpD_3)
`=destroy_2`(:tmpD_2)
`=destroy_2`(:tmpD_1)
`=destroy_2`(:tmpD)
`=destroy`(c1)
I just did the manual destroy in order to know what was going on.
How can I null out the pointer after freeing it? At the end of the day, it is the only way in which =destroy can perform the check if self.handle != nil:. Besides, Araq mentioned that compiler set it to nil.
Manually freeing is done like so:
`=destroy`(x)
`=wasMoved`(x)