Oh, I forgot to answer your last question. Best practice IMO is a wrapper, something along this (note: typed by heart, check especially parameters)
Code:
class SquirrelObject
{
public:
SquirrelObject(HSQUIRRELVM v,HSQOBJECT &i) : obj(i) {
sq_addref(v,&i);
};
SquirrelObject(HSQUIRRELVM v,SQInteger stackidx) {
sq_getstackobj(v,stackidx);
sq_addref(v,&obj);
};
~SquirrelObject() { sq_release(v,&obj); }
HSQOBJECT obj;
}
and then treat it as what it is - an object aka C++ class instance
I recommend adding all accesses and operations you need, too, and capsulate the members in private so you never ever end up fiddling around with HSQOBJECTs directly.
You could also additionally store the HSQUIRRELVM for convenience, which is safe for friend VMs/coroutines since a friend VM is basically just a stackframe for another "parent" VM)
Still, you need to take care of this object's lifetime - as usual regarding any class instance, as a C++ programmer you should be used to that.
Choose your destiny :-D