从回调中访问数据

时间:2011-10-14 02:37:24

标签: c++ callback global-variables

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

我知道绕过这个的唯一方法是添加一个指向我的struct的全局指针,以便回调知道在哪里找到数据,或者使用一堆boost类来从我的struct中创建一个假的函数指针回调使用。对于OOP限制而言,这两种选择更像是实际解决方案。

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

使数据“全球化”的理由:

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

但是,我希望避免一个缺点:

  • 即使数据位于单独的命名空间中(并且忽略了我是唯一一个编写此程序的人),也没有什么可以阻止程序的其他部分访问此数据。如果它发生了,我将没有简单的方法来跟踪它。

到目前为止,我唯一的想法就是将全局数据包装在一个未命名的命名空间中。对于所有意图和目的,这应该使其对代码库的其余部分不可见,并消除不使用全局变量的最常见原因。但是,这也意味着 需要访问它的代码必须全部包含在一个文件中,如果该文件变大,这可能会变得很麻烦。

还有其他选择我没有考虑过,或者这是不是很好?

3 个答案:

答案 0 :(得分:2)

您可以使用一些模板化的静态函数来为您提供数据指针,但您必须在编译时指定它们:

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

只要您为每次通话使用唯一的数据/ ID模板参数组合,就不会有任何问题。

答案 1 :(得分:1)

至于保护您的全局状态不被意外使用,您可以将其包装在一个类中,将成员标记为私有品尝,并将回调函数声明为朋友。

答案 2 :(得分:0)

将您的数据放入一个类并实例化此类 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);
}