从回调中访问数据

发布于 2024-12-09 15:36:36 字数 801 浏览 0 评论 0原文

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

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

因此,我正在争论是否完全放弃该结构,并将其转换为独立的代码和数据。本质上,数据将成为全局的(或更可能的是,包装在全局结构中),但将在其名称空间的范围内。

使数据成为“全局”的理由:

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

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

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

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

还有其他我没有想到的选择吗?或者这已经是最好的选择了吗?

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 as it gets?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

人间不值得 2024-12-16 15:36:36

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

#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 模板参数组合,就不应该有任何问题。

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.

梦中的蝴蝶 2024-12-16 15:36:36

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

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.

送你一个梦 2024-12-16 15:36:36

将您的数据放入一个类中并实例化该类静态-盟友:

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

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);
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文