Accessing data from a callback
I have some code and data, both currently encapsulated within a struct, which in turn is within a namespace. I'm trying to integrate an external library, which makes use of old-fashioned callbacks. I need access to my data within the context of the callback, but the callback API provides no means of adding personalized parameters.
The only way I know to circumvent this is to either add a global pointer to my struct, so that the callback knows where to find the data, or use a tangle of boost classes to create a fake function pointer from my struct for the callback to use. Both options feel more like hacking around OOP limitations than actual solutions.
So, I'm debating whether or not to ditch the struct completely, and convert it to free-standing code and data. Essentially, the data would become global (or more likely, wrapped within a global struct), but would be within the confines of it's namespace.
Justification for making the data "global":
- The code has a single purpose in the program, and always uses the same set of data for the life of the program. The data is never allocated or freed.
- This code and data are never instanced. There never are and never will be multiple copies.
- I have no love for OOP (I use C++ because it is the best tool for the job), so I don't feel the need to keep it encapsulated on principle alone.
However, there is one downside that I would like to avoid:
- Even though the data is in a separate namespace (and ignoring the fact that I am the only person writing this program), there is nothing to prevent other parts of the program from accessing this data. And if it were to happen, I will have no easy way to track it.
The only idea I've had so far is to wrap the global data within an unnamed namespace. This should, for all intents and purposes, make it invisible to the rest of the code base, and remove the most common reason for not using globals. However, it also means that the code that does need to access it must all be contained within a single file, which could become a pain to work with if that file gets large.
Is there another option I'm not thinking of, or is this as good 开发者_如何学JAVAas it gets?
You could just some templated static functions to give you a data pointer, though you would have to specify these at compile time:
#include <iostream>
using namespace std;
template <class Data, int ID>
struct ext_library_context
{
static Data data;
static void callback()
{
// callback code, using data
cout << data << endl;
}
};
template <class Data, int ID>
Data ext_library_context<Data, ID>::data;
void ext_library_call(void callback())
{
callback();
}
int main()
{
int d1 = 1;
ext_library_context<int, 1>::data = d1;
int d2 = 2;
ext_library_context<int, 2>::data = d2;
ext_library_call(ext_library_context<int, 1>::callback);
ext_library_call(ext_library_context<int, 2>::callback);
}
As long as you use a unique Data/ID template parameter combination for each call, you shouldn't have any issues.
As for protecting your global state from unintended use, you could wrap it in a class, mark members as private to taste, and declare the callback functions as friends.
Put your data in a class and instantiate this class static-ally:
class MyClass {
private:
Data data; // variables which you avoid declaring globally
public:
void real_callback() {
do_something(data);
}
};
void callback() {
static MyClass my_class; // here is the trick.
my_class.real_callback();
// Or you can instantiate it on heap
// static auto my_class = new MyClass;
// my_class->real_callback();
}
int main() {
old_function_wanting_a_callback(callback);
}
精彩评论