从回调中访问数据



我有一些代码和数据,它们目前都封装在一个结构体中,而结构体又在一个名称空间中。我正在尝试集成一个外部库,它利用了老式的回调。我需要在回调上下文中访问我的数据,但是回调API没有提供添加个性化参数的方法。

我知道规避这一点的唯一方法是向我的结构添加一个全局指针,以便回调知道在哪里找到数据,或者使用一堆boost类从我的结构中创建一个假的函数指针供回调使用。这两个选项感觉更像是绕过OOP的限制,而不是真正的解决方案。

所以,我正在讨论是否要完全放弃结构体,并将其转换为独立的代码和数据。从本质上讲,数据将成为全局的(或者更有可能,包装在全局结构中),但将在其名称空间的范围内。

将数据设为"global"的理由:

  • 代码在程序中只有一个目的,并且在程序的整个生命周期中始终使用同一组数据。数据永远不会被分配或释放。
  • 这些代码和数据永远不会被实例化。从来没有,也永远不会有多个副本。
  • 我不喜欢OOP(我使用c++是因为它是这项工作的最佳工具),所以我觉得没有必要仅仅在原则上把它封装起来。

然而,有一个缺点我想避免:

  • 即使数据在单独的名称空间中(并且忽略我是唯一编写此程序的人这一事实),也没有什么可以阻止程序的其他部分访问该数据。如果它发生了,我将没有简单的方法来跟踪它。
到目前为止,我唯一的想法是将全局数据包装在一个未命名的名称空间中。出于所有的意图和目的,这应该使它对代码库的其余部分不可见,并消除不使用全局变量的最常见原因。然而,这也意味着需要访问的代码必须全部包含在一个文件中,如果该文件变大,处理起来可能会很麻烦。

是否有其他的选择我没有想到,或者这是最好的,因为它得到?

您可以只使用一些模板化的静态函数来提供数据指针,尽管您必须在编译时指定这些函数:

#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);
}

只要为每个调用使用唯一的Data/ID模板参数组合,就不会有任何问题。

为了保护全局状态不被意外使用,可以将其包装在一个类中,将成员标记为private,并将回调函数声明为友元。

把你的数据放到一个类中并实例化这个类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);
}

相关内容

  • 没有找到相关文章

最新更新