【问题标题】:Advice on wrapping third party libraries关于包装第三方库的建议
【发布时间】:2010-11-02 21:48:37
【问题描述】:

我已经在一家公司的计算机视觉部门担任软件开发人员一年了。我的主要工作是将第三方软件集成到一个框架中,所以我通常最终会编写包装库,因为很多第三方软件并没有按照我们希望的方式工作(不是线程安全的,a * * 使用等)。

通常我只是包装整个库并使用互斥保护对库的调用(线程安全在某种程度上是大多数外部库的主要问题)。我真的很喜欢这样做,因为它会让你进入很多有趣的情况,并且你会看到很多有趣的代码。但是,我经常认为我做得不好,或者我的实现不是很好。我觉得我缺乏一些关于如何正确地做这样的事情的设计知识。

基本上,我想知道是否有任何好的指导方针或提示来设计一个适当的“在损坏的 API 之上的 API”,或者这是否总是会变得非常丑陋和丑陋。

【问题讨论】:

    标签: c++ c api


    【解决方案1】:

    前几天我会在这里引用另一个问题的答案

    1. 您当前的方法是否通过了测试?
    2. 够快吗?

    如果是,请继续做你正在做的事情。

    作为替代方案

    只需确保您的新 API 包含原始 API 的预期功能和常规意外功能。还要确保它呈现“适合用途”的重新呈现。看看 FOSS 项目中 C 库的 C++ 包装,例如 GTK/GTK for C++(它只是包装了前者)。

    如果 API 被破坏,修复它并提交一个补丁......与第三方合作(我假设可以访问源代码意味着他们不会介意这一点)......你可以重新编写他们的一些 API 是“包装友好”的,并建议他们合并一些更改。如果有问题,请成为解决问题的人。

    没什么大不了的,只需用 B 包裹 A 并确保 B 做 A 应该做的,或用于做的事情。

    【讨论】:

    • 谢谢,这以某种方式增强了我的信心;)我通常不会遇到任何速度或语义问题,但通常代码并不像我想要的那样干净。但我想没有其他办法,因为我没有第三方库的来源。
    【解决方案2】:

    我可以添加到Aiden's response 的唯一一件事是,您还应该考虑用RAII 技术替换需要显式初始化和终止的代码。当我面临提供 API 的外观时,我似乎总是遇到这样的类:

    struct ADVERTISER {
        /* a bunch of members here */
    };
    
    void adv_Initialize(ADVERTISER *adv, /* a bunch of arguments */);
    void adv_DoStuff(ADVERTISER *adv);
    void adv_Terminate(ADVERTISER *adv);
    

    我已经看到它以以下方式包装在 C++ 类中:

    namespace wrapper {
      class Advertiser {
      public:
          Advertiser(): inited_(false) {}
          void initialize(/* a bunch of arguments */) {
            terminate();
            adv_Initialize(&adv_, ...);
            inited_ = true;
          }
          void doStuff() {
            validate();
            adv_DoStuff(&adv_);
          }
          void terminate() {
            if (inited_) {
                adv_Terminate(&adv_);
                inited_ = false;
            }
          }
      protected:
          void validate() {
            if (!inited_) {
                throw std::runtime_error("instance is not valid");
            }
          }
      private:
          ADVERTISER adv_;
          bool inited_;
      };
    }
    

    问题在于Advertiser 类并没有真正使API 更易于使用,甚至更清洁恕我直言。如果你遇到这样的情况,那么:

    1. 使用完全参数化的构造函数来确保不存在无效实例
    2. 清理析构函数中的所有资源
    3. 如果有意义,请编写一个复制构造函数和赋值运算符将它们设为私有而不实现它们。

    我的目标是确保我呈现/创建/包装的任何 API 都适用于我们现有的编码风格。我还尝试将 API 转变为一种比当前更加面向对象的风格。我已经看到了许多我称之为 面向对象的 C 的东西,就像我上面介绍的那样。如果你想让它们真正适合 C++,那么就让它们真正面向对象并利用 C++ 为你提供的优势:

    • 小心管理任何状态变量。
    • 如果复制等操作没有意义,请隐藏它们。
    • 如果有任何泄漏资源的可能性,请找到一些方法来防止它发生(通常使用 RAII 会有所帮助)。
    • 使用构造函数限制实例的创建,以消除无效实例和其他极端情况。

    【讨论】:

    • 谢谢,我认为这是一些非常好的建议,尤其是对我来说,因为我有很强的 C 背景,所以我对 C++ 还很陌生。
    • 不客气。在切换到 C++ 之前,我花了很多年在嵌入式平台上做 C,所以我完全可以理解。我发现如果你让你的包装器更好地适应 C++ 会产生很大的不同——这样你就可以通过包装其他 API 获得一些东西。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多