albertodemichelis / squirrel

Official repository for the programming language Squirrel
http://www.squirrel-lang.org
MIT License
894 stars 148 forks source link

May I ask if it is possible to implement a destructor function #276

Closed Lenheart357 closed 9 months ago

Lenheart357 commented 9 months ago

Due to some development requirements, I hope to call a function to perform necessary operations when the class is destroyed. Can this be achieved

rversteegen commented 9 months ago

From C/C++/etc you can use sq_setreleasehook() to set a callback on a class, instance, or userdata which will be called immediately before it's deleted. (For some reason, an instance's releasehook can cancel deletion by incrementing the refcount, the others can't, that's an oversight.) There's no way to set a hook from a Squirrel script (unless you do it via a C wrapper function).

However it's not so easy to read data from the fields of an instance from the release hook. You would have ahead of time use sq_getstackobj to get an pointer to the instance, store this in a C struct (store a pointer to this in the instance using sq_setinstanceup), then when the release hook is called use sq_pushobject from push the pointer onto the stack -- which sounds dangerous, there may be some contexts in which it would crash -- before you can read from it using the usual API. (If you're using Quirrel (or willing to just copy-paste the function into Squirrel's source) then you can use (the undocumented) sq_direct_get() to read from an class/instance without needing to push it. Probably quite safe to do inside the release hook.)

rversteegen commented 9 months ago

Come to think of, pushing and popping an object from within its release hook would cause its refcount to go 0 -> 1 -> 0 and it'd be freed again, recursively. So need to manually increment its refcount first. Aside from that, looking at the code some more I think it would actually work, since it doesn't reenter the VM.

And if you're wondering, what about adding destructor metamethods (written in Squirrel)? Well there's absolutely no way they could be implemented to run immediately when the refcount hits zero, like the release hook is, because that can happen in a hundred places where reentering the VM is impossible. However, the release hook could increment an instance's refcount and put it on a list to be destructed later.

Lenheart357 commented 9 months ago

Thank you. I used your suggestion and called the C closure during Squirrel Class Object construction

In C, sq_ Set releasehook and store the data I need in the new struct so that I can call the data in the destructor. Finally, I release the struct in the destructor and destroy the memory