代码之家  ›  专栏  ›  技术社区  ›  jdt141

库初始化和关闭的通用模式?

  •  8
  • jdt141  · 技术社区  · 16 年前

    是否有一种模式可用于调用底层(C)库所需的初始化和清理例程?在我的例子中,我想创建包装器类,以便将其组合到其他对象中。问题是,当我销毁包装器类时,底层库的清理例程被调用。在我实例化包装器类的多个对象之前,这没关系。我的问题是什么是 最好的 如何真正处理这种情况?我想到了一个静态参考计数器,但我想知道是否还有其他可能更好的选择和涉及的交易。

    5 回复  |  直到 16 年前
        1
  •  4
  •   Warren Young    16 年前

    不是每件事都必须是一门课。Singleton模式可以让您将其转换为一个类,但它实际上并不能为您购买任何全局函数:

    bool my_library_init();
    void my_library_shutdown();
    

    如果库已成功初始化,则第一个调用将返回true,第二个调用将安静地执行需要执行的任何操作并退出。您可以在这些接口后面添加任何引用计数或线程跟踪类型的内容。

    另外,不要忽视您的库可能能够透明地完成所有这些工作。当调用第一个库函数时,它是否可以检测到它尚未初始化,并在执行工作之前设置所有内容?对于shutdown,只需用一个全局对象注册要销毁的资源,这样当程序退出时它们就会被销毁。这样做当然更为棘手,但可能值得您的库的调用者从可用性方面获益。

        2
  •  6
  •   Emile Cormier    16 年前

    如果可以在main启动之前调用初始化,在main结束之后调用清理,那么这个小技巧(hack?)可能适合您:

    #include <iostream>
    
    // C library initialization routine
    void init() {std::cout << "init\n";}
    
    // C library cleanup routine
    void fini() {std::cout << "fini\n";}
    
    // Put this in only one of your *.cpp files
    namespace // anonymous
    {
        struct Cleaner
        {
            Cleaner() {init();}
            ~Cleaner() {fini();}
        };
        Cleaner cleaner;
    };
    
    int main()
    {
        std::cout << "using library\n";
    }
    

    输出:

    init
    using library
    fini
    

    它使用(滥用?)这样一个事实:静态对象的构造函数在main之前调用,析构函数在main之后调用。这就像整个节目的RAII。

        3
  •  1
  •   Matthieu M.    16 年前

    Singleton 谈谈,所以我只能推荐一看 Alexandrescu's work .

    但是我不确定你真的需要 那里因为如果你这么做了,你会假设你所有的电话都是共享状态的。。。是这样吗?当您通过不同的实例调用库时,您真的希望 Wrapper 要获取上次调用设置它的状态?

    如果没有,则需要序列化访问,并每次重新初始化数据。

    class Wrapper
    {
    public:
      Wrapper() { lock(Mutex()); do_init_c_library(); }
      ~Wrapper() { do_clean_up_c_library(); unlock(Mutex()); }
    
    private:
      static Mutex& Mutex() { static Mutex MMutex; return MMutex; }
    }; // class Wrapper
    

    很简单。。。尽管你需要确保 Mutex 正确初始化(一次)并一直有效,直到不再需要它。

    Boost 为 once issue ,因为我们使用基于堆栈的方法 MMutex

        4
  •  0
  •   sbi    16 年前

    如果可以更改库实现,则可以让对库函数之一的每次调用访问第一次使用时创建的单例。

    或者您将一个全局/静态变量放入库中,该库在构造期间对其进行初始化,并在销毁期间关闭它(如果库本身使用全局变量,并且初始化/关闭的顺序与全局变量冲突,那么这可能会变得很烦人。此外,链接器可能会决定删除未引用的全局变量…)

        5
  •  0
  •   Emile Cormier    16 年前

    Singleton 和 Facade 模式,使C库例程只能通过Facade调用。Facade确保了C库的初始化和清理。Singleton确保只有一个Facade实例。

    #include <iostream>
    
    // C library initialization and cleanup routines
    void init() {std::cout << "init\n";}
    void fini() {std::cout << "fini\n";}
    
    // C library routines
    void foo() {std::cout << "foo\n";}
    void bar() {std::cout << "bar\n";}
    
    
    class Facade // Singleton
    {
    public:
        void foo() {::foo();}
        void bar() {::bar();}
        static Facade& instance() {static Facade instance; return instance;}
    
    private:
        Facade() {init();}
        ~Facade() {fini();}
    };
    
    // Shorthand for Facade::instance()
    inline Facade& facade() {return Facade::instance();}
    
    
    int main()
    {
        facade().foo();
        facade().bar();
    }
    

    输出:

    init
    foo
    bar
    fini