I have a simple Lua script
function TestFunction(Id)
local Factory = TestParent();
local ChildDirect = TestChild("DirectCall");
local ChildFactory1 = Factory:CreateChild("Factory1");
local ChildFactory2 = Factory:CreateChild("Factory2");
result = Ret()
return result
end
that uses two C++ exposed objects (trough luabind)
void TestParent::RegisterToLua(lua_State* lua)
{
// Export our class with LuaBind
luabind::module(lua)
[
luabind::class_<TestParent>("TestParent")
.def(luabind::constructor<>())
.def("CreateChild", &TestParent::CreateChild)
];
}
void TestChild::RegisterToLua(lua_State* lua)
{
// Export our class with LuaBind
luabind::module(lua)
[
luabind::class_<TestChild>("TestChild")
.def(luabind::constructor<std::string>())
.def("GetValue", &TestChild::GetValue)
];
}
I call the function
luabind::object obj = luabind::call_function< luabind::object >(LuaState, "TestFunction", IdParam);
if ( obj.is_valid() )
{
....
}
lua_gc(LuaState, LUA_GCCOLLECT, 0);
During lua_gc call only Factory and ChildDirect objects are destroyed. ChildFactory1 and ChildFactory2 remains allocated. The lua stack remains balanced (has same value - 5 - some tables ) after the luabind::call_function.
What is the problem ? The objects created by Factory remain somehow referenced ? By who ?
CreateChild body is
TestChild* TestParent::CreateChild(std::string strname)
{
return new TestChild(strname);
}
The ownership of the new constructed object should be taken by lua object and destroyed if ChildFactory1 or ChildFactory2 is nil-ed or out of scope.
adopt: Used to transfer ownership across language boundaries.
module(L)
[
def("create", &create, adopt(result))
];
You should return a smart pointer (i.e. a boost::shared_ptr) from your factory.
see: LuaBind Documentation # smart pointer
and a discussion in the LuaBridge docu
Related
I have a C++ object which inherits from node::ObjectWrap. The object itself manages the resource so it accepts it as an argument in a private constructor.
When object is created from Javascript it's quite straightforward:
void New(const v8::FunctionCallbackInfo<v8::Value>& args) {
// ...
auto handleToCustomResource = resolveFromJSArg(args[0]->ToString());
auto object = new MyObjectWrap(handleToCustomResource);
object->Wrap(args.This());
args.GetReturnValue().Set(args.This());
}
However it's not clear how to wrap the object when it originates from C++, here is my recent effort:
public v8::Local<v8::Object> CreateObject(v8::Isolate *isolate, const char *name) {
v8::Local<v8::Context> context = isolate->GetCurrentContext();
v8::EscapableHandleScope scope(isolate);
auto object = new MyObjectWrap(handleToMyCustomResource);
v8::Local<v8::Object> instance = // eh don't have an instance??
object->Wrap(instance);
return scope.Escape(instance);
}
How to properly create a JS object so I could use it as an instance for my native object?
One of workarounds I found is to basically have two constructors, one public and one private and then inherit one from another. The public one is available in javascript, while the private is solely used to create an instance for wrapping an existing ObjectWrap object.
v8::Local<v8::FunctionTemplate> privTpl = v8::FunctionTemplate::New(isolate, PrivateNew);
v8::Local<v8::FunctionTemplate> pubTpl = v8::FunctionTemplate::New(isolate, New);
// define prototype
pubTpl->Inherit(privTpl);
exports->Set(v8::String::NewFromUtf8(isolate, "MyObject"), tpl->GetFunction());
There is a model inherited from QAbstractListModel, I use it in qml. One of the properties of this model are parameters, they are specific to the element type of this model. That is one element the parameters of this class TemperatureParam, DifrentParamType another, a third still something... How can I pass an object to qml and to be sure that the memory is freed after use? The code below now works as I need to, but it seems to me that it's not safe.
Param class is so trivial:
class QuickTemperatureParam : public QObject
{
Q_OBJECT
Q_PROPERTY(float param1 READ param1 WRITE setParam1)
//...
};
Model class (Here's what I'm asking):
class SectionsModel : public QAbstractListModel
{
//...
QVariant data(const QModelIndex &idx, int role = Qt::DisplayRole) const override
{
//...
int type = getType( idx );
if (type == 1)
{
auto p = new QuickTemperatureParam( idx );
p->deleteLater(); // This is all right or no?
return qVariantFromValue(p);
}
else if (type == 2)
//...
}
};
QML something like this:
ListView {
model: sectionsModel
delegate: Rectangle {
color: model.statusColor
ItemDelegate {
text: model.title
highlighted: ListView.isCurrentItem
onPressed:
switch ( model.type )
{
case SectionType.Temperature:
temperatureParam.openItem(model)
break;
case SectionType.Lighting:
lightingParam.open(model)
break;
}
}
}
}
Popup {
id: temperatureParam
function openItem(model)
{
var p = model.param
params.itemAt(0).range.from = params.itemAt(1).range.from = p.min
params.itemAt(0).range.to = params.itemAt(1).range.to = p.max
params.itemAt(0).range.setValues( p.dayMin, p.dayMax )
params.itemAt(1).range.setValues( p.nightMin, p.nightMax )
open()
}
}
According to the documentation:
When data is transferred from C++ to QML, the ownership of the data
always remains with C++. The exception to this rule is when a QObject
is returned from an explicit C++ method call: in this case, the QML
engine assumes ownership of the object, unless the ownership of the
object has explicitly been set to remain with C++ by invoking
QQmlEngine::setObjectOwnership() with QQmlEngine::CppOwnership
specified.
Generally an application doesn't need to set an object's ownership explicitly. As you can read here, by default, an object that is created by QML has JavaScriptOwnership.
Objects returned from C++ method calls will be set to JavaScriptOwnership also but this applies only to explicit invocations of Q_INVOKABLE methods or slots.
Because the method data is not an explicit C++ method call, you should consider to set the object ownership to QQmlEngine::JavaScriptOwnership calling setObjectOwnership()
So, in general:
Don't use QQmlEngine::CppOwnership if you want QML to destroy the object. The associated data will be deleted when appropriate (i.e. after the garbage collector has discovered that there are no more live references to the value)
A QSharedPointer probably wouldn't work. You have more information here.
Assigning names to my objects (like the ones returned from the global Instantiate method) is breaking my tests. Anyone have any ideas for how to get around such things in test?
using System;
using NUnit.Framework;
using UnityEngine;
[TestFixture()]
public class BoardSpec{
[Test()]
public void NamePropertyWorks(){
var obj = new UnityEngine.Object();
obj.name = "object name";
}
}
The error I'm receiving: System.MissingMethodException : Cannot find the requested method.
The first line of the stack trace gives: at (wrapper managed-to-native) UnityEngine.Object:set_name (string)
Unity 5.2.0f3, running tests in MonoDevelop-Unity 4.0.1 on osx
_____update 9/20______
It sounds like creating new Objects is not recommended, but this code fails with the same error:
[Test()]
public void ScriptableObjectNamePropertyWorks(){
var obj = new ScriptableObject();
obj.name = "object name";
}
Short answer: Never create nor inherit directly form UnityEngine.Object, use ScriptableObject instead
Doing something like (new UnityEngine.Object()).name = "text" will always throw a null reference exception, as I'll explain below. From there to the System.MissingMethodException you are getting, it depends on the inner workings of NUnit.
Unity uses UnityEngine.Object in a very special way, keeping track of objects, and considering some "not alive" despite existing. The Equals comparison for UnityEngine.Object is overriden to reflect this, and an existing Object might equal null:
// Both Mesh and MyObject inherit directly from UnityEngine.Object
Object plainObject = new UnityEngine.Object();
Mesh meshObject = new UnityEngine.Mesh();
MyNumber myNumber = new MyNumber(123456f);
// using the overriden Unity.Object.Equals()
print(plainObject != null); // false
print(meshObject != null); // true
print(myNumber != null); // false
// With traditional null checking, everything exists of course, as we just created them
print(plainObject as System.Object != null); // true
print(meshObject as System.Object != null); // true
print(myNumber as System.Object != null); // true
print(myNumber.number); // prints 123456, the object is there and perfectly operational
print(myNumber.name); // the program ends with a null reference exception thrown by the name set accessor, because myNumber is not "alive"
Every native Unity class that inherits from UnityEngine.Object makes any needed internal call to register the object as "alive", but this is not done in the base class itself. Basically, any attempt to create a vanilla Object, or something directly inherited from it, will be considered stillborn by the engine, and you won't get it to work as usual. If you need to create or inherit from Objects, use ScriptableObject instead, that has an explicitly special behaviour in the inner workings.
my native function should return an object but it returns the called function object. I am using the spidermonkey jsapi to extend my application. I define several classes which are proxies to their c++ counterparts. The usage is like a main object, called 'mx' used to create objects of type 'widget' using a function named 'widget'
Each application object has some kind of ID which can be passed to the js object constructor as an argument. In spidermonkey 1.8.5 i could create a js widget object using the mx widget method
function on_trigger( triggervalue )
{
w = mx.widget("somename");
print_console("mx is " + mx );
print_console("w is " + w );
}
But mx.widget("somename") does not return an object of type widget, it returns the function object:
mx is [object mx]
w is function widget() {
[native code]
}
This is how the jsapi classes and functions are implemented:
JSBool mx_wrapper_getwidget(JSContext* cx, unsigned argc, jsval* argv)
{
JSObject *global = JS_GetGlobalForScopeChain(cx);
jsval v;
JS_GetProperty(cx, global, widget_wrapper_class.name, &v);
JS::CallArgs args = JS::CallArgsFromVp(argc, argv);
JSObject *w = JS_New(cx, JSVAL_TO_OBJECT(v), argc, args.array());
args.rval().setObject( *w );
return JS_TRUE;
}
static JSFunctionSpec mx_wrapper_methods[] =
{
JS_FS("widget", mx_wrapper_getwidget, 1, 0),
JS_FS_END
};
JS_InitClass(cx, global, NULL, &mx_wrapper_class, mx_wrapper_cons, 0, mx_wrapper_properties, mx_wrapper_methods, NULL, NULL)
JS_DefineObject(cx, global, "mx", &mx_wrapper_class, mx_wrapper_proto, 0);
Why does JSBool mx_wrapper_getwidget() return the function object and not the newly created object?
All the best
Heiner
answering myself: among various other minor issues i did not define my class properly
wrong (widget_wrapper_finalize, JSCLASS_NO_OPTIONAL_MEMBERS missing):
static JSClass widget_wrapper_class =
{
MX_JS_WIDGET_CLASSNAME, JSCLASS_HAS_PRIVATE,
JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
JS_EnumerateStub, JS_ResolveStub, NULL
};
right:
static JSClass widget_wrapper_class =
{
MX_JS_WIDGET_CLASSNAME, JSCLASS_HAS_PRIVATE,
JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, widget_wrapper_finalize, JSCLASS_NO_OPTIONAL_MEMBERS
};
Consider the following example:
function Process()
local Container=NewContainer()
Container:On(EventType.Add,function()
Container:DoSomething()
end)
-- Does not Garbage Collect
end
In luabridge, I store the function() as LuaRef which extends the lifetime for the Container and it will not be GCed because it's a RefCountedObjectPtr
Here is a workaround that I use to use a weak table which works, but it looks ugly:
function Process()
local Container=NewContainer()
local ParamsTable={ Container=Container }
setmetatable(ParamsTable, { __mode = 'k' })
Container:On(EventType.Add,function()
ParamsTable.Container:DoSomething()
end)
-- Garbage Collects fine
end
Is there any way to have a LuaRef that functions similar to this? Or maybe there is another workaround?
Here is the way I approached this problem:
Create a wrapper class around C++ luabridge class (If you have class Display.A() in C++, create class A() in Lua)
Store a weak table inside that wrapper class (self.WeakTable={} and setmetatable(self.WeakTable, { __mode = 'k' }))
In the weak table, reference self: (self.WeakTable.self=self)
Pass self.WeakTable to C++ and store in as LuaRef - this will gc
Create a wrapper function like so:
Container:On(EventType.Add,function(WeakTableParams)
WeakTableParams.self.Callback();
end)