Because my userdata objects reference themselves, I need to delete and nil a variable for the garbage collector to work.
Lua code:
obj = object:new()
--
-- Some time later
obj:delete() -- Removes the self reference
obj = nil -- Ready for collection
C Code:
typedef struct {
int self; // Reference to the object
int callback; // Reference to a Lua function
// Other members and function references removed
} Object;
// Called from Lua to create a new object
static int object_new( lua_State *L ) {
Object *obj = lua_newuserdata( L, sizeof( Object ) );
// Create the 'self' reference, userdata is on the stack top
obj->self = luaL_ref( L, LUA_REGISTRYINDEX );
// Put the userdata back on the stack before returning
lua_rawgeti( L, LUA_REGISTRYINDEX, obj->self );
// The object pointer is also stored outside of Lua for processing in C
return 1;
}
// Called by Lua to delete an object
static int object_delete( lua_State *L ) {
Object *obj = lua_touserdata( L, 1 );
// Remove the objects self reference
luaL_unref( L, LUA_REGISTRYINDEX, obj->self );
return 0;
}
// Called from Lua to set a callback function
static int object_set_callback( lua_State *L ) {
Object *obj = lua_touserdata( L, 1 );
// Unref an existing callbacks
if ( obj->callback != 0 ) {
luaL_unref( L, LUA_REGISTRYINDEX, obj->callback );
obj->callback = 0;
}
// Set the new callback - function is on top of the stack
obj->callback = luaL_ref( L, LUA_REGISTRYINDEX );
}
// Called from C to call a Lua function for the obj
static void do_callback( Object *obj ) {
// Push the Lua function onto the stack
lua_rawgeti( L, LUA_REGISTRYINDEX, obj->callback );
// Push the userdata onto the stack
lua_rawgeti( L, LUA_REGISTRYINDEX, obj->self );
// Call the function
lua_call( L, 1, 0 );
}
Is there some way I can set the object to nil in Lua, and have the delete() method called automatically? Alternatively, can the delete method nil all variables that reference the object? Can the self reference be made 'weak'?
EDIT 1: I've included code to show why the object references itself; see the do_callback function. Each object is part of a tree-like structure, with the bulk of the processing done in C, but a user can set a custom Lua function that is called under certain conditions.
EDIT 2: Another possible solution comes to mind; Instead of each obj keeping a reference to itself, can I lookup the object in the global index when I need to pass it to Lua, using its address as a key?
You could try creating a weak table in the registry and store your references there, that way setting all references of your object to nil should make it available for the gc.
Related
Not sure if the terminology in the title is 100% correct, but what I mean is easily illustrated by this example:
class MyClass{
String str = '';
MyClass(this.str);
}
void main() {
MyClass obj1 = MyClass('obj1 initial');
print(obj1.str);
doSomething(obj1);
print(obj1.str);
doSomethingElse(obj1);
print(obj1.str);
}
void doSomething(MyClass obj){
obj.str = 'obj1 new string';
}
void doSomethingElse(MyClass obj){
obj = MyClass('obj1 new object');
}
This will print
obj1 initial
obj1 new string
obj1 new string
But what if I wanted doSomethingElse() to actually modify what obj1 is referencing, so that the output would be:
obj1 initial
obj1 new string
obj1 new object
Is this possible in Dart, and if so, how?
No, Dart does not pass arguments by reference. (Without something like C++'s complex type system and rules, it's not clear how it would work if the caller didn't bind the argument to a variable.)
You instead could add a level of indirection (i.e., by putting obj1 inside another object, such as a List, Map, or your own class). Another possibility would be to make doSomethingElse a nested function, and then it could directly access and modify variables in the enclosing scope.
You have a reference problem in that function,
When you call doSomethingElse(obj1) in main your,
MyObject obj parameter referencing the obj1 value,
then obj you're referencing the MyClass('obj1 new objcet'),
and you're not changing the obj1 reference in the main
void doSomethingElse(MyClass obj){ // let's say we gave the parameter obj1
// here obj referencing the obj1 value
obj = MyClass('obj1 new object');
//and then it is referencing the MyClass('obj1 new object') value
//nothing change for obj1 it still referencing the same value
}
You can return that object and give reference to that object like this,
class MyClass {
String str = '';
MyClass(this.str);
}
void main() {
MyClass obj1 = MyClass('obj1 initial');
print(obj1.str);
doSomething(obj1);
print(obj1.str);
obj1 = doSomethingElse();
print(obj1.str);
}
void doSomething(MyClass obj) {
obj.str = 'obj1 new string';
}
MyClass doSomethingElse() {
return MyClass('obj1 new object');
}
output :
See update 1 below for my guess as to why the error is happening
I'm trying to develop an application with some C#/WPF and C++. I am having a problem on the C++ side on a part of the code that involves optimizing an object using GNU Scientific Library (GSL) optimization functions. I will avoid including any of the C#/WPF/GSL code in order to keep this question more generic and because the problem is within my C++ code.
For the minimal, complete and verifiable example below, here is what I have. I have a class Foo. And a class Optimizer. An object of class Optimizer is a member of class Foo, so that objects of Foo can optimize themselves when it is required.
The way GSL optimization functions take in external parameters is through a void pointer. I first define a struct Params to hold all the required parameters. Then I define an object of Params and convert it into a void pointer. A copy of this data is made with memcpy_s and a member void pointer optimParamsPtr of Optimizer class points to it so it can access the parameters when the optimizer is called to run later in time. When optimParamsPtr is accessed by CostFn(), I get the following error.
Managed Debugging Assistant 'FatalExecutionEngineError' : 'The runtime
has encountered a fatal error. The address of the error was at
0x6f25e01e, on thread 0x431c. The error code is 0xc0000005. This error
may be a bug in the CLR or in the unsafe or non-verifiable portions of
user code. Common sources of this bug include user marshaling errors
for COM-interop or PInvoke, which may corrupt the stack.'
Just to ensure the validity of the void pointer I made, I call CostFn() at line 81 with the void * pointer passed as an argument to InitOptimizer() and everything works. But in line 85 when the same CostFn() is called with the optimParamsPtr pointing to data copied by memcpy_s, I get the error. So I am guessing something is going wrong with the memcpy_s step. Anyone have any ideas as to what?
#include "pch.h"
#include <iostream>
using namespace System;
using namespace System::Runtime::InteropServices;
using namespace std;
// An optimizer for various kinds of objects
class Optimizer // GSL requires this to be an unmanaged class
{
public:
double InitOptimizer(int ptrID, void *optimParams, size_t optimParamsSize);
void FreeOptimizer();
void * optimParamsPtr;
private:
double cost = 0;
};
ref class Foo // A class whose objects can be optimized
{
private:
int a; // An internal variable that can be changed to optimize the object
Optimizer *fooOptimizer; // Optimizer for a Foo object
public:
Foo(int val) // Constructor
{
a = val;
fooOptimizer = new Optimizer;
}
~Foo()
{
if (fooOptimizer != NULL)
{
delete fooOptimizer;
}
}
void SetA(int val) // Mutator
{
a = val;
}
int GetA() // Accessor
{
return a;
}
double Optimize(int ptrID); // Optimize object
// ptrID is a variable just to change behavior of Optimize() and show what works and what doesn't
};
ref struct Params // Parameters required by the cost function
{
int cost_scaling;
Foo ^ FooObj;
};
double CostFn(void *params) // GSL requires cost function to be of this type and cannot be a member of a class
{
// Cast void * to Params type
GCHandle h = GCHandle::FromIntPtr(IntPtr(params));
Params ^ paramsArg = safe_cast<Params^>(h.Target);
h.Free(); // Deallocate
// Return the cost
int val = paramsArg->FooObj->GetA();
return (double)(paramsArg->cost_scaling * val);
}
double Optimizer::InitOptimizer(int ptrID, void *optimParamsArg, size_t optimParamsSizeArg)
{
optimParamsPtr = ::operator new(optimParamsSizeArg);
memcpy_s(optimParamsPtr, optimParamsSizeArg, optimParamsArg, optimParamsSizeArg);
double ret_val;
// Here is where the GSL stuff would be. But I replace that with a call to CostFn to show the error
if (ptrID == 1)
{
ret_val = CostFn(optimParamsArg); // Works
}
else
{
ret_val = CostFn(optimParamsPtr); // Doesn't work
}
return ret_val;
}
// Release memory used by unmanaged variables in Optimizer
void Optimizer::FreeOptimizer()
{
if (optimParamsPtr != NULL)
{
delete optimParamsPtr;
}
}
double Foo::Optimize(int ptrID)
{
// Create and initialize params object
Params^ paramsArg = gcnew Params;
paramsArg->cost_scaling = 11;
paramsArg->FooObj = this;
// Convert Params type object to void *
void * paramsArgVPtr = GCHandle::ToIntPtr(GCHandle::Alloc(paramsArg)).ToPointer();
size_t paramsArgSize = sizeof(paramsArg); // size of memory block in bytes pointed to by void pointer
double result = 0;
// Initialize optimizer
result = fooOptimizer->InitOptimizer(ptrID, paramsArgVPtr, paramsArgSize);
// Here is where the loop that does the optimization will be. Removed from this example for simplicity.
return result;
}
int main()
{
Foo Foo1(2);
std::cout << Foo1.Optimize(1) << endl; // Use orig void * arg in line 81 and it works
std::cout << Foo1.Optimize(2) << endl; // Use memcpy_s-ed new void * public member of Optimizer in line 85 and it doesn't work
}
Just to reiterate I need to copy the params to a member in the optimizer because the optimizer will run all through the lifetime of the Foo object. So it needs to exist as long as the Optimizer object exist and not just in the scope of Foo::Optimize()
/clr support need to be selected in project properties for the code to compile. Running on an x64 solution platform.
Update 1: While trying to debug this, I got suspicious of the way I get the size of paramsArg at line 109. Looks like I am getting the size of paramsArg as size of int cost_scaling plus size of the memory storing the address to FooObj instead of the size of memory storing FooObj itself. I realized this after stumbling across this answer to another post. I confirmed this by checking the value of paramsArg after adding some new dummy double members to Foo class. As expected the value of paramsArg doesn't change. I suppose this explains why I get the error. A solution would be to write code to correctly calculate the size of a Foo class object and set that to paramsArg instead of using sizeof. But that is turning out to be too complicated and probably another question in itself. For example, how to get size of a ref class object? Anyways hopefully someone will find this helpful.
I'm not sure whether I'm misusing Vala or GLib.Regex, because I'm new to both. I've created a minimal example, which reproduces the error. From the following code, I'd expect that it prints a INPUTX b six times, prefixed with source and result alternatingly:
public class Test
{
public static void run( string src )
{
var regex = new Regex( "INPUT[0-9]" );
for( int i = 0; i < 3; ++i )
{
stdout.printf( #"-- source: $src\n" );
src = regex.replace( src, -1, 0, "value" );
stdout.printf( #"-- result: $src\n\n" );
}
}
public static void main()
{
Test.run( "a INPUTX b" );
}
}
I wrote this code based on the example in the docs. However, after compiling with valac Test.vala --pkg glib-2.0 and running, I get:
-- source: a INPUTX b
-- result: a INPUTX b
-- source: -- source:
-- result: N�
-- source: -- source:
-- result: PN�
What am I doing wrong?
After looking into the generated C code, I concluded that this rather is a Vala-related issue: Vala puts a g_free to the end of the loop's body, which frees the memory returned by g_regex_replace, and that is referenced by src. But why does Vala do that?
The reason is that (see)
arguments are, by default, unowned.
Hence, when we assign the string object returned by regex.replace to the unowned string src, that reference is (see)
not recorded in the object
and the Vala compile considers it to be safe to dispose - although it's not quiet clear, why this happens particularly at the end of the loop's body.
So the straiht-forward solution is to declare the src argument as owned.
Consider this (nonsense) code:
string foo (string s)
{
return s;
}
void run (string src)
{
var regex = new Regex( "INPUT[0-9]" );
for( int i = 0; i < 3; ++i )
{
stdout.printf( #"-- source: $src\n" );
//src = regex.replace( src, -1, 0, "value" );
src = foo (src);
stdout.printf( #"-- result: $src\n\n" );
}
}
void main ()
{
run( "a INPUTX b" );
}
The Vala compiler (rightfully) complains:
test.vala:13.2-13.16: error: Invalid assignment from owned expression to unowned variable
src = foo (src);
^^^^^^^^^^^^^^^
So there must be something different for methods from vapi files, since it allows the call to Regex.replace ().
I smell a bug somewhere (either in the compiler or the vapi), but I'm not sure.
In OpenCV I want to return the point position like Point(x,y) to the main() function that I click on the image in the mouse callback function . Is there anyway other than setting a global variable?
I don't want to write all the codes inside the on_mouse() function.
Thanks
to expand Safirs idea there, apart from a class or such, you could just pass in the point itself:
void on_mouse( int e, int x, int y, int d, void *ptr )
{
Point*p = (Point*)ptr;
p->x = x;
p->y = y;
}
Point p;
namedWindow("win");
setMouseCallback("win",on_mouse, (void*)(&p) );
// changed value of p will be accessible here
You can avoid using global variables by passing a pointer to your data as a parameter to setMouseCallback(). Agree with #berek, just wanted to show a full example below to avoid confusion about global variables.
using namespace cv;
void on_mouse( int e, int x, int y, int d, void *ptr )
{
Point*p = (Point*)ptr;
p->x = x;
p->y = y;
}
in main() {
Point p;
namedWindow("window");
Mat image = imread("someimage.jpg");
imshow(image);
//pass a pointer to `p` as parameter
setMouseCallback("window",on_mouse, &p );
// p will update with new mouse-click image coordinates
// whenever user clicks on the image window
}
No, this isn't possible, since the on_mouse() is a callback function. Here is the opencv documentation of it.
So, "global" variables are the only way to solve this problem. Alternatively, if you're looking for a nicer solution, you can create a wrapper class in which you have the namedWindow and the MouseCallback and a private member variable, which is manipulated when mouse callback function is called.
Does Dart support the concept of variable functions/methods? So to call a method by its name stored in a variable.
For example in PHP this can be done not only for methods:
// With functions...
function foo()
{
echo 'Running foo...';
}
$function = 'foo';
$function();
// With classes...
public static function factory($view)
{
$class = 'View_' . ucfirst($view);
return new $class();
}
I did not found it in the language tour or API. Are others ways to do something like this?
To store the name of a function in variable and call it later you will have to wait until reflection arrives in Dart (or get creative with noSuchMethod). You can however store functions directly in variables like in JavaScript
main() {
var f = (String s) => print(s);
f("hello world");
}
and even inline them, which come in handy if you are doing recusion:
main() {
g(int i) {
if(i > 0) {
print("$i is larger than zero");
g(i-1);
} else {
print("zero or negative");
}
}
g(10);
}
The functions stored can then be passed around to other functions
main() {
var function;
function = (String s) => print(s);
doWork(function);
}
doWork(f(String s)) {
f("hello world");
}
I may not be the best explainer but you may consider this example to have a wider scope of the assigning functions to a variable and also using a closure function as a parameter of a function.
void main() {
// a closure function assigned to a variable.
var fun = (int) => (int * 2);
// a variable which is assigned with the function which is written below
var newFuncResult = newFunc(9, fun);
print(x); // Output: 27
}
//Below is a function with two parameter (1st one as int) (2nd as a closure function)
int newFunc(int a, fun) {
int x = a;
int y = fun(x);
return x + y;
}