C++: static function wrapper that routes to member function? - c++

I've tried all sorts of design approaches to solve this problem, but I just can't seem to get it right.
I need to expose some static functions to use as callback function to a C lib. However, I want the actual implementation to be non-static, so I can use virtual functions and reuse code in a base class. Such as:
class Callbacks {
static void MyCallBack() { impl->MyCallBackImpl(); }
...
class CallbackImplBase {
virtual void MyCallBackImpl() = 0;
However I try to solve this (Singleton, composition by letting Callbacks be contained in the implementor class, etc) I end up in a dead-end (impl usually ends up pointing to the base class, not the derived one).
I wonder if it is at all possible or if I'm stuck with creating some sort of helper functions instead of using inheritance?

Problem 1:
Though it may look and seem to work on your setup this is not guaranteed to work as the C++ ABI is not defined. So technically you can not use C++ static member functions as functions pointers to be used by C code.
Problem 2:
All C callacks (that I know of) allow you to pass user data back as a void*. You can use this as the pointer to your object that has the virtual method. BUT You must make sure you use dynamic_cast<>() to the base class (the one with the virtual method used in the callback) before it is converted into the void* otherwise the pointer at the other end may not be interpreted correctly (especially if there is multiple inheritance involved).
Problem 3:
Exceptions: C is not designed to work with exceptions (especially old C libraries with callbacks). So don't expect exceptions that escape your callback to provide anything meaningful to the caller (they are more likely to result in application termination).
Solution:
What you need to do is use extern "C" function as the callback that calls the virtual method on an object of know type and throws away all exceptions.
An example for the C pthread routines
#include <iostream>
extern "C" void* start_thread(void* data);
class Work
{
public:
virtual ~Work() {}
virtual void doWork() = 0;
};
/*
* To be used as a callback for C code this MUST be declared as
* with extern "C" linkage to make sure the calling code can
* correctly call it
*/
void* start_thread(void* data)
{
/*
* Use reinterpret_cast<>() because the only thing you know
* that you can do is cast back to a Work* pointer.
*
*/
Work* work = reinterpret_cast<Work*>(data);
try
{
work->doWork();
}
catch(...)
{
// Never let an exception escape a callback.
// As you are being called back from C code this would probably result
// in program termination as the C ABI does not know how to cope with
// exceptions and thus would not be able to unwind the call stack.
//
// An exception is if the C code had been built with a C++ compiler
// But if like pthread this is an existing C lib you are unlikely to get
// the results you expect.
}
return NULL;
}
class PrintWork: public Work
{
public:
virtual void doWork()
{
std::cout << "Hi \n";
}
};
int main()
{
pthread_t thread;
PrintWork printer;
/*
* Use dynamic_cast<>() here because you must make sure that
* the underlying routine receives a Work* pointer
*
* As it is working with a void* there is no way for the compiler
* to do this intrinsically so you must do it manually at this end
*/
int check = pthread_create(&thread,NULL,start_thread,dynamic_cast<Work*>(&printer));
if (check == 0)
{
void* result;
pthread_join(thread,&result);
}
}

It's possible. Perhaps there's a problem on how you're initializing the concrete implementation?
In fact, I remember one library that does something very similar to this. You might find it usefull to take a look at libxml++ source code. It's built on top of libxml, which is a C library.
libxml++ uses a struct of static functions to handle the callbacks. For customization, the design allows the user to provide (through virtual functions) his/her own implementations to which the callbacks are then forwarded. I guess this is pretty much your situation.

Something like the below. The singleton is in class Callback, the Instance member will return a statically allocated reference to a CallbackImpl class. This is a singleton because the reference will only be initialised once when the function is first called. Also, it must be a reference or a pointer otherwise the virtual function will not work.
class CallbackImplBase
{
public:
virtual void MyCallBackImpl() = 0;
};
class CallbackImpl : public CallbackImplBase
{
public:
void MyCallBackImpl()
{
std::cout << "MyCallBackImpl" << std::endl;
}
};
class Callback
{
public:
static CallbackImplBase & Instance()
{
static CallbackImpl instance;
return instance;
}
static void MyCallBack()
{
Instance().MyCallBackImpl();
}
};
extern "C" void MyCallBack()
{
Callback::MyCallBack();
}

Are any of the parameters passed to the callback function user defined? Is there any way you can attach a user defined value to data passed to these callbacks? I remember when I implemented a wrapper library for Win32 windows I used SetWindowLong() to attach a this pointer to the window handle which could be later retrieved in the callback function. Basically, you need to pack the this pointer somewhere so that you can retrieve it when the callback gets fired.
struct CALLBACKDATA
{
int field0;
int field1;
int field2;
};
struct MYCALLBACKDATA : public CALLBACKDATA
{
Callback* ptr;
};
registerCallback( Callback::StaticCallbackFunc, &myCallbackData, ... );
void Callback::StaticCallbackFunc( CALLBACKDATA* pData )
{
MYCALLBACKDATA* pMyData = (MYCALLBACKDATA*)pData;
Callback* pCallback = pMyData->ptr;
pCallback->virtualFunctionCall();
}

Related

Invoking non static class member function of dynamically loaded library

I am writing an app with optional runtime dependency with KWallet. It means if there is KWallet installed on user system it's used and if not it still works but without KWallet support.
Here is how I load the library, it's a static property of my wrapper class. Then in the constructor under condition of state I resolve symbols from the library.
QLibrary Core::PSE::KWallet::lib("KF5Wallet");
...
lib.load();
openWallet = (OpenWallet) lib.resolve("_ZN7KWallet6Wallet10openWalletERK7QStringyNS0_8OpenTypeE");
networkWallet = (NetworkWallet) lib.resolve("_ZN7KWallet6Wallet13NetworkWalletEv");
destructor = (Destructor) lib.resolve("_ZN7KWallet6WalletD2Ev");
The same as the QLibrary - function are also static members of my class, but I'm not sure if that's a good idea.
Here are definitions from my class
typedef ::KWallet::Wallet* (*OpenWallet)(const QString &, WId, ::KWallet::Wallet::OpenType);
typedef QString (*NetworkWallet)();
typedef void (*WalletOpened)(bool);
typedef void (*Destructor)();
static OpenWallet openWallet;
static NetworkWallet networkWallet;
static Destructor destructor;
Here is how I allocate an object
wallet = openWallet(networkWallet(), 0, ::KWallet::Wallet::Asynchronous);
Everything goes fine until the point I need to execute non static members and, especially, destructor. As far as I know, it is supposed to look like that
((*wallet).(destructor))()
but that doesn't seem to work. I'm totally new to this topic and I have no idea even if I had started in a right way.
So, how do I invoke the destructor of this way loaded class? How do I invoke the rest of it's members? Or shall I better do it in some completely other way?
P.S. I'm aware, there is a DBUS API for KWallet, even some wrapper libraries like qtkeychain, but I want to understand the way of making this kind of dependencies using this example.
I have found the solution.
The idea is to write a small shared library with wrapper functions like that
extern "C" KWallet::Wallet* openWallet(const QString &name, WId w, KWallet::Wallet::OpenType ot = KWallet::Wallet::Synchronous) {
return KWallet::Wallet::openWallet(name, w, ot);
}
extern "C" void deleteWallet(KWallet::Wallet* w) {
w->deleteLater();
}
extern "C" const char* networkWallet() {
return KWallet::Wallet::NetworkWallet().toStdString().c_str();
}
extern "C" int readPassword(KWallet::Wallet* w, const QString &key, QString &value) {
return w->readPassword(key, value);
}
Let's call this little wrapper foo.so. So, then you build this foo.so and target link at build time to the real dependency, KWallet in my case.
Then in the main code you're going to try dynamically load this foo.so, not the KWallet itself. And if the KWallet is absent on the launching machine this foo.so is simply not going to load, that's the trick I had to know!
Then of course you simply resolve symbols like this
QLibrary Core::PSE::KWallet::lib("foo");
...
lib.load();
openWallet = (OpenWallet) lib.resolve("openWallet");
networkWallet = (NetworkWallet) lib.resolve("networkWallet");
deleteWallet = (DeleteWallet) lib.resolve("deleteWallet");
readPassword = (ReadPassword) lib.resolve("readPassword");
And call it like this
wallet = openWallet(networkWallet(), 0, ::KWallet::Wallet::Asynchronous);
...
QString password;
int result = readPassword(wallet, *i, password);
...
deleteWallet(wallet);
Before going into solution I should state that this is very bad idea and I can't see a sensible reason to go this way except if you are using a class from a compiled shared library which you can't edit its source and the class has no alternative virtual interface .
The better way to do this in c++ is to use virtual methods by making a base class containing the functionality you need to use and any subclass in a shared library can override those virtual methods to customize the behaviour .
Now this is the solution to your case :
A non static method of a class has a calling convention of thiscall which means that they are like ordinary functions except they take a pointer to the class instance as the first argument , this is the this pointer ! In fact methods in c++ (non virtual) are syntactic sugar for c functions which operate on a struct
This snippet of code illustrates :
struct somestruct
{
int j;
};
void add(somestruct* this, int i)
{
this->j += i;
}
class someclass
{
public:
void add(int i)
{
j += i;
}
private:
int j;
};
So in your case : for each method declaration add a pointer to the class instance that is the first argument and when you want to call this method on an instance just pass it as the first pointer.
Virtual functions are implemented in two ways :
1 - a vtable inside the class itself like c vtables
2 - a pointer to vtable inside the class so you only have one vtable per class declaration and it's said that this method is better for cache hence it's used by most compilers

Is this usage of gcroot safe?

I need to use an unmanaged API from C++/CLI. This API stores a void pointer to arbitrary user data and a few callbacks. It then eventually calls those callbacks, passing the user data in as void*.
So far I had a native class passing its "this" pointer as the user data, and using that pointer to have the API call back into this class, i.e.:
static void __stdcall Callback(void* userData) {
((MyType*)userData)->Method();
}
class MyType {
public:
MyType() { RegisterWithApi((void*)this, Callback); }
void Method();
};
I'm trying to translate this using a managed class. I found that the type gcroot can be used to safely store a managed reference in native code, so here's how I'm doing it now:
// This is called by the native API
static void __stdcall Callback(void* userData) {
// Cast back to gcroot and call into managed code
(*(gcroot<MyType^>*)userData)->Method();
}
ref class MyType {
gcroot<MyType^>* m_self;
public:
MyType() {
m_self = new gcroot<MyType^>;
RegisterWithApi((void*)m_self, Callback);
}
~MyType() { delete m_self; }
// Method we want called by the native API
void Method();
}
While this seems fine to the C++/CLI compiler, I am not perfectly re-assured. From what I understand, gcroot somehow keeps track of its managed reference as it is moved by the GC. Will it manage to do this while stored as a void* by unmanaged code? Is this code safe?
Thanks.
This is what I ended up doing and it works perfectly. The purpose of gcroot is to store a managed reference on the native heap, which is precisely what I'm doing here.
No! It's exactly the other way around. gcroot is a native class template. You use it to store a handle to managed memory in a native type which is compiled with clr support. You will typically use it to divert calls to member functions of a native object to a managed object stored in a member of type gcroot.
EDIT: I was on mobile yesterday where typing code examples is a bit awkward... The intended and typical usage of gcroot<T^> is somewhere along these lines:
// ICallback.h
struct ICallback {
virtual void Invoke() = 0;
virtual void Release() = 0;
protected:
~ICallback() {}
};
That is what your native apps or libraries see and include. Then, you have a mixed component compiled with CLR support, which implements ICallback and stores a handle to some managed object in a gcroot<ManagedType^>:
// Callback.cpp (this translation unit must be compiled with /clr)
// I did not compile and test, but you get the point...
template<class T^> class Callback : public ICallback {
gcroot<T^> m_Managed;
virtual void Invoke()
{
m_Managed->Invoke();
}
virtual void Release()
{
delete this;
}
public:
Callback(T^ p_Managed) : m_Managed(p_Managed) {}
};
__declspec( dllexport ) ICallback* CreateCallback()
{
auto t_Managed = gcnew SomeManagedType();
return new Callback<System::Action^>(
gcnew System::Action(t_Managed, &SomeManagedType::Method));
}
Your native apps call CreateCallback, recieve an instance of ICallback which when Invoke-d calls a method of managed type, held in gcroot<System::Action^>...

Nested Classes C++ static inner methods (Xml parsing and trying to populate vector with values)

So this is what I am trying to accomplish. I am trying to use a sax parser to parse some XML. it looks like I need to call all their methods as statics. So if I want to pass a value back from say startElement it is static void startElement. Which brings me to my example code. I have been pulling my hair on how to update a value in a Nesting class from a static member function.
I have looked at several things such as defining OuterClass * oc; then trying to reference oc->allRecords, but since it is a static method inside, it fails. I am sure I am doing something wrong architecturally, so any feedback on what would be the right way to do this would be a great help. Thanks.
class Attribute {
string AttributeName;
string AttributeValue;
};
typedef shared_ptr<Attribute> AttributePtr;
class AttributeSet {
vector<AttributePtr> Attributes;
};
typedef shared_ptr<AttributeSet> AttributeSetPtr;
class OuterClass {
public :
vector<AttributeSetPtr> allRecords;
class InnerClass {
public:
static mymethod1() {
// I need to be able to set attributes here :
// This would be the characters method for sax parsing
// What is the right way to Attributes.push_back(new Attribute(Name,Value));
}
static mymethod2() {
// I also need to be able to add Records here :
// This would be the endElement for sax parsing
// What is the right way to allRecords.push_back(AttributeSet);
}
};
// EDIT: CALLING CODE GOES HERE (WAS EDITED - SEE BELOW)
};
// ADDING INFORMATION REGARDING HOW METHOD 1 & 2 are called
xmlSAXHandler saxHandler;
memset(&saxHandler, 0, sizeof(saxHandler));
saxHandler.initialized = XML_SAX2_MAGIC;
...
saxHandler.endElementsNs = &InnerClass::method2;
saxHandler.characters = &InnerClass::method1;
...
InnerClass innerXmlParsingClass
xmlSaxUserParseMemory( &saxHandler, &innerXmlParsingClass, xmlString, xmlString.length());
Your mistake is using an inner class (are you coming from Java?).
I don't know what you believe you are are achieving with an inner class, but it won't work. Don't use inner classes in C++ unless you really know what it does (for inner classes, protected and private members of the outer classes are seen as if they were public).
Now, as the solution to your problem, I guess it depends on the implementation you're using (I used once Apache's Xerces SAX, but I know Microsoft offers its own SAX implementation, and that there should be a lot other alternatives, so...)
Edit
After the comment, I found the following tutorial:
http://www.jamesh.id.au/articles/libxml-sax/libxml-sax.html
I must say that, coming from Java to C++, and using a C API, you have a kind of courage...
:-D
If you are not familiar enough with function pointers, and C in general, using libxml2 will be a challenge. Be sure that in the end, you will understand those notions... Note that C have a way to handle the data that C++, Java or C# developers associate to this. The C way is to pass a pointer to your data (the user data) to a function, and when the callback is called, it passes back this pointer, typed as a void *. You must then cast it back to its right type, and voilà, you have your this back.
:-)
Anyway, reading the doc, I see that when you parse the file, you'll call the following C function:
int xmlSAXUserParseFile( xmlSAXHandlerPtr sax,
void * user_data,
const char * filename);
the user_data part is the one that interest you because it enables you to have a context. So, wrapping this function in a C++ class, you could have something like:
// MySaxBase.hpp
class MySaxBase
{
public :
MySaxBase() ;
int parseFile(const std::string & p_filename) ;
virtual void startDocument() ;
virtual void endDocument() ;
private :
static void do_startDocument(void *p_user_data) ;
static void do_endDocument(void *p_user_data) ;
xmlSAXHandler m_sax ;
}
.
// MySaxBase.cpp
extern "C"
{
void do_startDocument(void *p_user_data)
{
// this static method will convert the p_user_data into
// the this pointer...
MySaxBase * saxBase = static_cast<MySaxBase *>(p_user_data) ;
// ...and call the right virtual method
saxBase->startDocument() ;
}
void do_endDocument(void *p_user_data)
{
// this static method will convert the p_user_data into
// the this pointer...
MySaxBase * saxBase = static_cast<MySaxBase *>(p_user_data) ;
// ...and call the right virtual method
saxBase->endDocument() ;
}
} // extern "C"
MySaxBase::MySaxBase()
{
// the m_sax structure must be set to zero to NULL all its
// pointers to functions
memset(&m_sax, 0, sizeof(xmlSAXHandler)) ;
// Now, we initialize some pointers to the static method we
// want to be called
this->m_sax.startDocument = do_startDocument ;
this->m_sax.endDocument = do_endDocument ;
}
int MySaxBase::parseFile(const std::string & p_filename)
{
// the important thing, here, is the this pointer, passed as
// a user_data parameter
return xmlSAXUserParseFile(&m_sax, this, p_filename.c_str()) ;
}
void MySaxBase::startDocument()
{
// The document started. Override this method to
// actually do something
}
void MySaxBase::endDocument()
{
// The document ended. Override this method to
// actually do something
}
I did not test this, and I never used libxml2, but I guess the code must be Ok, and this should be enough for you to continue on your own: Just add the methods you want to support, initialize the sax handler with the relevant function pointers, and you'll have your class complete.
The MySaxBase::startDocument and MySaxBase::endDocument methods are virtual just for you to derive from MySaxBase and then override those methods.
Edit 2
I'll reproduce here Steve Jessop's excellent comment:
+1. One tiny quibble - I don't think that static member functions are guaranteed by the C++ standard to have C linkage / calling convention, but to use them as a callback from a C API, that's what they need. I don't specifically know what implementations it makes a difference, but for safety do_startDocument should be a free function declared with extern "C". On the same subject: a Java programmer may not realise you have make sure that the function can't throw an exception (because C doesn't have them). So you'd normally want to see a try/catch(...) in the wrapper function. – Steve Jessop
Following this, and after reading Johannes Schaub - litb (who else?) no less excellent answer at static vs extern "C"/"C++" , I modified the code to make do_startDocument and do_endDocument real C functions (i.e. wrapped in an extern "C" block). This usually is not important (I never encountered this kind of problem), but, better safe than sorry.
Your basic problem is that static methods are not per-instance, so there is no this pointer. You somehow need to get a OuterClass* passed to mymethod1 and mymethod2.
If you show us how mymethod1 and mymethod2 are called, we can help you further.
If it's simply called by you someplace where you have a OuterClass object, then your solution is simple:
class OuterClass
{
// ...
static void mymethod1(OuterClass* oc)
{
oc->all_records.push_back( something );
}
};
void some_func()
{
OuterClass oc;
OuterClass::method1(&oc);
}
Since you updated your question here is how you should do this:
class OuterClass {
public:
vector<AttributeSetPtr> allRecords;
void characters(const xmlChar* ch, int len)
{
// do here whatever you want
allRecords.push_back(bla bla);
}
static void static_characters(void* ctx, const xmlChar* ch, int len) {
// retrieve this pointer from ctx
static_cast<OuterClass*>(ctx)->characters(ch, len);
}
};
saxHandler.characters = &OuterClass::static_characters;
...
OuterClass outerClass;
xmlSaxUserParseMemory(&saxHandler, static_cast<void*>(&outerClass), xmlString, xmlString.length());

handling pointer to member functions within hierachy in C++

I'm trying to code the following situation:
I have a base class providing a framework for handling events. I'm trying to use an array of pointer-to-member-functions for that. It goes as following:
class EH { // EventHandler
virtual void something(); // just to make sure we get RTTI
public:
typedef void (EH::*func_t)();
protected:
func_t funcs_d[10];
protected:
void register_handler(int event_num, func_t f) {
funcs_d[event_num] = f;
}
public:
void handle_event(int event_num) {
(this->*(funcs_d[event_num]))();
}
};
Then the users are supposed to derive other classes from this one and provide handlers:
class DEH : public EH {
public:
typedef void (DEH::*func_t)();
void handle_event_5();
DEH() {
func_t f5 = &DEH::handle_event_5;
register_handler(5, f5); // doesn't compile
........
}
};
This code wouldn't compile, since DEH::func_t cannot be converted to EH::func_t. It makes perfect sense to me. In my case the conversion is safe since the object under this is really DEH. So I'd like to have something like that:
void EH::DEH_handle_event_5_wrapper() {
DEH *p = dynamic_cast<DEH *>(this);
assert(p != NULL);
p->handle_event_5();
}
and then instead of
func_t f5 = &DEH::handle_event_5;
register_handler(5, f5); // doesn't compile
in DEH::DEH()
put
register_handler(5, &EH::DEH_handle_event_5_wrapper);
So, finally the question (took me long enough...):
Is there a way to create those wrappers (like EH::DEH_handle_event_5_wrapper) automatically?
Or to do something similar?
What other solutions to this situation are out there?
Thanks.
Instead of creating a wrapper for each handler in all derived classes (not even remotely a viable approach, of course), you can simply use static_cast to convert DEH::func_t to EH::func_t. Member pointers are contravariant: they convert naturally down the hierarchy and they can be manually converted up the hierarchy using static_cast (opposite of ordinary object pointers, which are covariant).
The situation you are dealing with is exactly the reason the static_cast functionality was extended to allow member pointer upcasts. Moreover, the non-trivial internal structure of a member function pointer is also implemented that way specifically to handle such situations properly.
So, you can simply do
DEH() {
func_t f5 = &DEH::handle_event_5;
register_handler(5, static_cast<EH::func_t>(f5));
........
}
I would say that in this case there's no point in defining a typedef name DEH::func_t - it is pretty useless. If you remove the definition of DEH::func_t the typical registration code will look as follows
DEH() {
func_t f5 = static_cast<func_t>(&DEH::handle_event_5);
// ... where `func_t` is the inherited `EH::func_t`
register_handler(5, f5);
........
}
To make it look more elegant you can provide a wrapper for register_handler in DEH or use some other means (a macro? a template?) to hide the cast.
This method does not provide you with any means to verify the validity of the handler pointer at the moment of the call (as you could do with dynamic_cast in the wrapper-based version). I don't know though how much you care to have this check in place. I would say that in this context it is actually unnecessary and excessive.
Why not just use virtual functions? Something like
class EH {
public:
void handle_event(int event_num) {
// Do any pre-processing...
// Invoke subclass hook
subclass_handle_event( event_num );
// Do any post-processing...
}
private:
virtual void subclass_handle_event( int event_num ) {}
};
class DEH : public EH {
public:
DEH() { }
private:
virtual void subclass_handle_event( int event_num ) {
if ( event_num == 5 ) {
// ...
}
}
};
You really shouldn't be doing it this way. Check out boost::bind
http://www.boost.org/doc/libs/1_43_0/libs/bind/bind.html
Elaboration:
First, I urge you to reconsider your design. Most event handler systems I've seen involve an external registrar object that maintains mappings of events to handler objects. You have the registration embedded in the EventHandler class and are doing the mapping based on function pointers, which is much less desirable. You're running into problems because you're making an end run around the built-in virtual function behavior.
The point of boost::bindand the like is to create objects out of function pointers, allowing you to leverage object oriented language features. So an implementation based on boost::bind with your design as a starting point would look something like this:
struct EventCallback
{
virtual ~EventCallback() { }
virtual void handleEvent() = 0;
};
template <class FuncObj>
struct EventCallbackFuncObj : public IEventCallback
{
EventCallbackT(FuncObj funcObj) :
m_funcObj(funcObj) { }
virtual ~EventCallbackT() { }
virtual void handleEvent()
{
m_funcObj();
}
private:
FuncObj m_funcObj;
};
Then your register_handler function looks something like this:
void register_handler(int event_num, EventCallback* pCallback)
{
m_callbacks[event_num] = pCallback;
}
And your register call would like like:
register_handler(event,
new EventCallbackFuncObj(boost::bind(&DEH::DEH_handle_event_5_wrapper, this)));
Now you can create a callback object from an (object, member function) of any type and save that as the event handler for a given event without writing customized function wrapper objects.

Reconciling classes, inheritance, and C callbacks

In my C++ project, I've chosen to use a C library. In my zeal to have a well-abstracted and simple design, I've ended up doing a bit of a kludge. Part of my design requirement is that I can easily support multiple APIs and libraries for a given task (due, primarily, to my requirement for cross-platform support). So, I chose to create an abstract base class which would uniformly handle a given selection of libraries.
Consider this simplification of my design:
class BaseClass
{
public:
BaseClass() {}
~BaseClass() {}
bool init() { return doInit(); }
bool run() { return doWork(); }
void shutdown() { destroy(); }
private:
virtual bool doInit() = 0;
virtual bool doWork() = 0;
virtual void destroy() = 0;
};
And a class that inherits from it:
class LibrarySupportClass : public BaseClass
{
public:
LibrarySupportClass()
: BaseClass(), state_manager(new SomeOtherClass()) {}
int callbackA(int a, int b);
private:
virtual bool doInit();
virtual bool doWork();
virtual void destroy();
SomeOtherClass* state_manager;
};
// LSC.cpp:
bool LibrarySupportClass::doInit()
{
if (!libraryInit()) return false;
// the issue is that I can't do this:
libraryCallbackA(&LibrarySupportClass::callbackA);
return true;
}
// ... and so on
The problem I've run into is that because this is a C library, I'm required to provide a C-compatible callback of the form int (*)(int, int), but the library doesn't support an extra userdata pointer for these callbacks. I would prefer doing all of these callbacks within the class because the class carries a state object.
What I ended up doing is...
static LibrarySupportClass* _inst_ptr = NULL;
static int callbackADispatch(int a, int b)
{
_inst_ptr->callbackA(a, b);
}
bool LibrarySupportClass::doInit()
{
_inst_ptr = this;
if (!libraryInit()) return false;
// the issue is that I can't do this:
libraryCallbackA(&callbackADispatch);
return true;
}
This will clearly do Bad Things(TM) if LibrarySupportClass is instantiated more than once, so I considered using the singleton design, but for this one reason, I can't justify that choice.
Is there a better way?
You can justify that choice: your justification is that the C library only supports one callback instance.
Singletons scare me: It's not clear how to correctly destroy a singleton, and inheritance just complicates matters. I'll take another look at this approach.
Here's how I'd do it.
LibrarySupportClass.h
class LibrarySupportClass : public BaseClass
{
public:
LibrarySupportClass();
~LibrarySupportClass();
static int static_callbackA(int a, int b);
int callbackA(int a, int b);
private:
//copy and assignment are rivate and not implemented
LibrarySupportClass(const LibrarySupportClass&);
LibrarySupportClass& operator=(const LibrarySupportClass&);
private:
static LibrarySupportClass* singleton_instance;
};
LibrarySupportClass.cpp
LibrarySupportClass* LibrarySupportClass::singleton_instance = 0;
int LibrarySupportClass::static_callbackA(int a, int b)
{
if (!singleton_instance)
{
WHAT? unexpected callback while no instance exists
}
else
{
return singleton_instance->callback(a, b);
}
}
LibrarySupportClass::LibrarySupportClass()
{
if (singleton_instance)
{
WHAT? unexpected creation of a second concurrent instance
throw some kind of exception here
}
singleton_instance = this;
}
LibrarySupportClass::~LibrarySupportClass()
{
singleton_instance = 0;
}
My point is that you don't need to give it the external interface of a canonical 'singleton' (which e.g. makes it difficult to destroy).
Instead, the fact that there is only one of it can be a private implementation detail, and enforced by a private implementation detail (e.g. by the throw statement in the constructor) ... assuming that the application code is already such that it will not try to create more than one instance of this class.
Having an API like this (instead of the more canonical 'singleton' API) means that you can for example create an instance of this class on the stack if you want to (provided you don't try to create more than one of it).
The external constraint of the c library dictates that when your callback is called you don't have the identification of the "owning" instance of the callback. Therefore I think that your approach is correct.
I would suggest to declare the callbackDispatch method a static member of the class, and make the class itself a singleton (there are lots of examples of how to implement a singleton). This will let you implement similar classes for other libraries.
Dani beat me to the answer, but one other idea is that you could have a messaging system where the call back function dispatch the results to all or some of the instances of your class. If there isn't a clean way to figure out which instance is supposed to get the results, then just let the ones that don't need it ignore the results.
Of course this has the problem of performance if you have a lot of instances, and you have to iterate through the entire list.
The problem the way I see it is that because your method is not static, you can very easily end up having an internal state in a function that isn't supposed to have one, which, because there's a single instance on the top of the file, can be carried over between invocations, which is a -really- bad thing (tm). At the very least, as Dani suggested above, whatever methods you're calling from inside your C callback would have to be static so that you guarantee no residual state is left from an invocation of your callback.
The above assumes you have static LibrarySupportClass* _inst_ptr declared at the very top. As an alternative, consider having a factory function which will create working copies of your LibrarySupportClass on demand from a pool. These copies can then return to the pool after you're done with them and be recycled, so that you don't go around creating an instance every time you need that functionality.
This way you can have your objects keep state during a single callback invocation, since there's going to be a clear point where your instance is released and gets a green light to be reused. You will also be in a much better position for a multi-threaded environment, in which case each thread gets its own LibrarySupportClass instance.
The problem I've run into is that because this is a C library, I'm required to provide a C-compatible callback of the form int (*)(int, int), but the library doesn't support an extra userdata pointer for these callbacks
Can you elaborate? Is choosing a callback type based on userdata a problem?
Could your callback choose an instance based on a and/or b? If so, then register your library support classes in a global/static map and then have callbackADispatch() look up the correct instance in the map.
Serializing access to the map with a mutex would be a reasonable way to make this thread-safe, but beware: if the library holds any locks when it invokes your callback, then you may have to do something more clever to avoid deadlocks, depending on your lock hierarchy.