【问题标题】:How to execute an auto-setup function如何执行自动设置功能
【发布时间】:2017-05-02 16:07:46
【问题描述】:

在开发依赖于另一个第三方库的库时,我遇到了第三方库绝对是垃圾需要手动调用全局设置和清理函数的问题。

int main()
{
    setup();
    //do stuff
    cleanup();
}

现在,这是 一个彻头彻尾的 sh*t show 在应用程序代码中并不是什么大问题,因为它只是在语法上很可怕,但实际上是库中的一个痛苦。

该库应该将这些奇怪的实现细节抽象出来,并且要求用户调用设置函数就像打我自己的脸。

我试图让它们消失

//namespace scope
struct AutoMagic
{
    AutoMagic() {setup();}
    ~AutoMagic() {cleanup();}
};
AutoMagic automagic;

然后我意识到这不会像这里和那里看到的那样跨翻译单元工作

因此标题中的问题。

【问题讨论】:

  • 我想这是一个见仁见智的问题,在我看来,手动设置/拆卸是正确的方法。它为该库的用户提供了更多控制权。如果我想/需要在启动该库之前做某事怎么办?如果有一些配置选项可以在启动之前/启动时传递给它怎么办?现在,如果您想自动执行此操作,请继续执行您所做的操作。它会起作用,我的意思是它会在main 开始之前的某个时间调用setup。为什么要关心全局初始化器的顺序?
  • @AndreyTurkin 用户可能需要全局变量。在这种情况下,事情会破裂。意见不同,但我不希望我的库带有警告:“你不能有来自这个库的全局变量”,或者“如果在安装之前调用这个库,程序是不正确的”。这种行为也会通过库层传播,这意味着最终用户可能与实际设置相距甚远,以至于代码看起来像一粒尘埃
  • 用户可以使用全局变量,除非某些全局构造函数使用该库,否则一切都会正常工作。在这种情况下,您有依赖关系,而可怜的 3rd 方库作者无论如何都没有机会做正确的事情(他/她应该如何处理让您满意?)我知道的唯一选择案例是使用 std::call_once 之类的东西检查和初始化每个公共 API 函数中的库。
  • @AndreyTurkin 我的库依赖于第三方库,我需要致电setup() 以使我的库正常工作。如果用户决定他想要一个来自我的库的类型的全局变量,他不能。因为他不知道设置是否完成。我在每个公共 API 中都考虑了类似于 std::call_once 的内容,但我认为这不会使库非常易于维护和无错误。
  • 那么...你的图书馆有一些共享状态吗?让事情变得更有趣 - 使用非平凡的构造函数;比如说,一些受全局互斥体保护的全局缓存?如果没有,想象一下(因为确实如此——第 3 方库的初始化基本上是共享状态)。现在,您将如何确保您的库用户可以在其全局变量中使用您的库 API?现在想象一下,有些库用户希望确保他们的一些代码在您的库执行任何事情之前运行,然后他们希望在您的库清理所有事情之后运行他们的一些代码i>.

标签: c++ initialization raii


【解决方案1】:

你可以试试这样的:

std::shared_ptr<AutoMagic> init(){
    static std::shared_ptr<AutoMagic> ptr(new AutoMagic{});
    return ptr;
}

并且在每个翻译单元中都这样做:

auto libMagic = init();

我没有测试它,但是首先调用 init() 的翻译单元应该创建对象,最后卸载的 shared_ptr 应该调用析构函数。

【讨论】:

  • 语法可能有点混乱,但我希望你能理解并能够弄清楚其余部分。我目前无法测试。
  • 这并没有解决问题,我不想随时随地要求这种设置/拆卸代码。这可能是不可避免的,但人们总是可以希望
  • 嗯,你实际上并不需要它在任何地方和无论如何 - 你只需要它在全局对象的初始化依赖于以前称为 init 的翻译单元中 - 但你必须以某种方式调用它无论如何。对于加载您的库的用户,您的所有全局对象都将在他可以调用函数/实例化对象之前被初始化,因此对于这个来说,您的库中的单个 shared_ptr 就足够了。
  • 问题是如何让用户甚至不知道发生了设置,而不是如何让用户安全设置。一个库就是为了做到这一点,如果可能的话,实现细节应该是 100% 不透明的。
【解决方案2】:

最后,唯一可行的就是不可移植的编译器特定代码

AutoMagic automagic __attribute__((init_priority(420));

不可移植,基本上所有主流编译器都支持这个,除了msvc。

该属性强制变量在所有没有该属性的变量和优先级大于该变量的变量之前初始化。

这说明确实存在对初始化优先级保证的需求,而且标准显然还没有给出。

【讨论】:

    【解决方案3】:

    可悲的是,您无法真正摆脱困境。您对全局实例有一个好主意,但实际上这对依赖项不太适用。除非您“使用”它或小心构建选项,否则它还有可能被链接器优化掉的进一步问题;我在共享库中的实体注册类实例中遇到了这个问题。

    两个可靠的选择:

    1. 将类似的cr*p 设置/拆卸函数添加到您自己的库中,这些函数遵循setup()cleanup()
    2. 更改库

    我会很抱歉,但这确实是第三方作者的错。所以你应该k*ll th*m他们道歉。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-03-11
      • 2018-09-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-01-21
      相关资源
      最近更新 更多