I have a game I am integrating with Lua scripting in order to allow customization.
I am using a C++ Lua wrapper:
https://github.com/tomaka/luawrapper
In my Lua script I am calling something like this:
function sprite_factory()
local sprite = sprite_new() -- register_new_sprite(name)
sprite:RegisterCallback("on_activate", function ()
sprite:SetState("closed")
end)
end
In my C++ code I have built a Sprite class and I'm using registerFunction to make the member methods available to Lua e.g. RegisterCallback is called on the sprite object returned by sprite_new()
bool RegisterCallback(const std::string hook, const std::function<void()> callback) {
callback();
mCallback = callback;
return true;
}
If I do the callback inside the RegisterCallback method, it works fine. However, I want to store the callback to be used as a raised event.
When I call this method later in my code:
void DoCallback() {
mCallback(); //raises exception
}
I get an exception:
libc++abi.dylib: terminating with uncaught exception of type
std::__1::bad_function_call: std::exception
I am declaring mCallback as a private:
std::function<void()> mCallback = NULL;
I'm not sure what is going on here.
I would suspect that there is an issue with the way mCallback is declared.
Related
I'm following the Node Addon API documentation to resolve a promise on the C++ side. On resolve I'd like to return a C++ object back to JS. My code is similar to what is here. The main difference is that I'd like to return an instance of the object below, which is Napi::ObjectWrap'ed:
class MyWrappedObject final : public Napi::ObjectWrap<MyWrappedObject> {
public:
static Napi::Object Init(Napi::Env env, Napi::Object exports) {} ;
MyWrappedObject(const Napi::CallbackInfo &info) : Napi::ObjectWrap<MyWrappedObject>(info) {};
}
i.e. in the async worker I'd like to resolve like so:
void OnOK() {
const auto wrapped_object = MyWrappedObject();
deferred.Resolve(Napi::Object::New(Env(), wrapped_object));
}
the issue here is that the ctor for Napi::ObjectWrap requires a Napi::CallbackInfo as argument but the context during the OnOK call doesn't provide that callback info. So I'm wondering what am I missing here, I've read the documents but cannot find any examples where they return a wrapped c++ object from a promise.
I'm writing a Node application (in TS) that needs to be interfaced with some native library.
I have a library (written in C) - let's consider it's a blackbox - and I'm writing a wrapper using NAN. The library native interface can be simplified into a following functions:
typedef void (*got_message_reply_cb)(context ctx, void * priv, struct X * the_reply);
context lib_connect();
bool lib_send_message(context ctx, message msg, got_message_reply_cb callback, void * priv);
I believe this is pretty straight-forward to understand.
So, I'm trying to wrap that black-box native library into something like:
class TheLibrary : public Nan::ObjectWrap {
Initialize(v8::Handle<v8::Object> target);
SendMessage(...)
}
And then to javascript object like:
class TheLibrary {
SendMessage(message: whatever, callback: (reply) => void); // or return promise, doesn't matter
}
How to do the actual handling of the callback in the NAN C++ module? I need to somehow pass the callback (represented probably by Local<Function> - which have, if I understand it correctly, limited scope) as a pointer to the function and then retrieve it back. How to do that? Thanks for your replies.
The high level answer is that you don't pass the JS callback function directly, but pass in a pointer to a function that somehow has your JS callback as a context value (in your example the priv parameter).
So for your case you write something like this:
void TheLibraryCallback(context ctx, void *instance, struct X *the_reply) {
((TheLibrary*)instance)->callback(ctx, the_reply);
}
In your TheLibrary you add a method void callback(context ctx, struct X * the_reply) that handles the callback. You call your library like this: lib_send_message(ctx, msg, TheLibraryCallback, this); with this being a TheLibrary instance.
So how do you call back the JS callback in your callback method? With nan you will have to make sure you are back in the main thread. There are examples out there, but I would suggest that you use the new N-API instead. The AsyncWorker helps with the boilerplate that you need to do to call the callback in the main thread.
I need to call a C++ method and pass in a callback method as a parameter... from ObjectiveC method...
This callback method would then be triggered multiple times in ObjectiveC... as it's a callback... and so then I need to trap that ObjectiveC callback method back as it will be called as a closure from Swift code...
This is the C++ Method Signature
static bool cPlusPlusMethodWithCallBack(const std::string& someText, void (*someCallback)(unsigned int) = NULL, unsigned int someNum = 0);
My Question is what should be the Block syntax of this Callback Method declared in ObjectiveC (in .mm and .h) which can then be passed as a parameter to this someCallback in C++
I am a Swift developer so bit stuck on ObjectiveC... Many Thanks
You can't pass an Objective-C block (or a Swift closure) as a function pointer argument like that. You'll need to create a separate, standalone function, and pass that in as the callback.
void MyCallback(unsigned int value)
{
// ...do something...
}
And in your main code:
cPlusPlusMethodWithCallBack("something", MyCallback);
Now, the downside of this is that in your callback, you'll often need to reference a particular Objective-C object in order to properly handle the callback. If that's something you need with this particular callback, you'll need to save it off somewhere as a static variable so that it can be accessed from the MyCallback function.
Alternatively, if you have control over the cPlusPlusMethodWithCallBack source code, you can update it to take a void * "reference" parameter, and then supply that parameter as an argument when you call the callback:
static void cPlusPlusMethodWithCallback(void (*callback)(void *ref), void *ref)
{
// ...really time consuming processing...
callback(ref);
}
Then, update your callback function:
void MyCallback(void *ref)
{
ObjectiveCObject *obj = (ObjectiveCObject *)ref;
[obj doSomething];
}
And when you initially call the method, just pass in the object you need as the reference parameter:
cPlusPlusMethodWithCallback(MyCallback, myObjectiveCObject);
I have a Button class which have an onClick std::function typed field and "setClickListener" method sets any lambda function to this std::function field as follows :
#include <functional>
class Button {
public:
void doSomething() {
if(onClick) {
onClick();
}
}
typedef std::function<void()> OnClickListener;
OnClickListener onClick;
void setClickListener(OnClickListener onClickCallBack) {
onClick = onClickCallBack;
}
};
In my application code, I am creating a lambda function and setting to onClick function of button as seen below :
#include "Button.h"
void onAnEventOccured() {
button->setClickListener([this]()->void {
// Do something
memberFunction();
anotherMemberFunction();
// etc...
});
}
void memberFunction() {
// Do some work...
}
void anotherMemberFunction() {
// Do some work...
}
Now, the critical section is that onAnEventOccured method called many times during the application's life cycle and the lambda function is set again and again. I am runnning on Visual Studio 2015 and putting debug trace point on the deconstructor of std::function class and can see it hits to tracepoint while setting setClickListener. I guess this is the deconstructor of lambda function which has been destroyed while leaving the scope of onAnEventOccured function and copy version of this lambda stored in Button instance as expected.
Am I correct on this? Is there any memory leak on this architecture?
Can't you call:
button->setClickListener([this]()->void {
// Do something
memberFunction();
anotherMemberFunction();
// etc...
});
in the constructor or during any other initialization method that you have on your Application code?
Also, your code could get an rvalue reference.
void setClickListener(OnClickListener&& callback);
I am trying to create a very simple event system to be used in a game. I have a EventManager class that looks something like this:
typedef std::function<void(IEvent* event)> CallbackType;
class EventManager
{
public:
void AddListener(const std::string eventName, IEventListener* listener)
{
CallbackType callback = std::bind(&IEventListener::HandleEvent, listener, std::placeholders::_1);
listeners[eventName].push_back(callback);
}
void AddListener(const std::string eventName, CallbackType callback)
{
// ...
}
void TriggerEvent(IEvent* event)
{
for (CallbackType callback : listeners[event->GetName()])
{
callback(event);
}
}
private:
std::map<std::string, std::vector<CallbackType>> listeners;
}
The 1st AddListener function works perfectly. The TriggerEvent function calls the HandleEvent function, which is implemented by each class that extends my IEventListener interface.
I would really like to be able to pass a callback to the 2nd AddListener function. This callback would then get called in the TriggerEvent function as before. I can pass in a callback constructed using std::bind and this works. For example:
eventManager->AddListener("WindowResize", std::bind(&MyClass::MemberFunction, this, std::placeholders::_1));
where MyClass extends the IEventListener interface. However, I'd really like to be able to just pass a simple function pointer instead:
eventManager->AddListener("WindowResize", this, &MyClass::MemberFunction);
Is this possible?
Edit
For anyone interested, I wrote a couple of macros that I think makes things a little cleaner.
#define MEMBER_CALLBACK(funPtr) \
std::bind(&funPtr, this, std::placeholders::_1)
#define MEMBER_CALLBACK_WITH_INSTANCE(funPtr, instancePtr) \
std::bind(&funPtr, instancePtr, std::placeholders::_1)
Now I can subscribe to an event by:
eventManager->AddListener("EventName", MEMBER_CALLBACK(MyClass::MemberFunction));
You can't pass a simple function pointer because MyClass::MemberFunction isn't a simple function. The std::bind() works because it associates an instance of MyClass with the reference to the member function. Without that information, the member function would not have access to the instance's data.