库初始化和关闭的常见模式?

时间:2010-02-07 05:20:02

标签: c++ design-patterns

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

5 个答案:

答案 0 :(得分:4)

并非一切都必须是一个班级。 Singleton模式可以让你把它变成一个类,但它实际上并没有为你买任何全局函数:

bool my_library_init();
void my_library_shutdown();

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

另外,不要忽视您的图书馆可以透明地完成所有这些操作的可能性。调用第一个库函数时,是否可以检测到它尚未初始化并在完成工作之前设置好所有内容?对于关闭,只需使用全局对象注册要销毁的资源,因此在程序退出时会销毁它们。这样做当然是比较棘手的,但可能值得你的图书馆来电者的可用性好处。

答案 1 :(得分:4)

如果可以在main启动之前调用初始化,并且在main结束后调用cleanup,那么这个小技巧(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。

答案 2 :(得分:1)

我已经看过很多Singleton谈话,所以我只能推荐一下Alexandrescu's work

但是我不确定你真的需要Singleton。因为如果你这样做,你会认为你所有的电话都要分享这个状态......是不是这样?当你通过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已正确初始化(一次)并且直到不再需要它为止。

Boostonce issue提供了设施,因为我们使用基于堆栈的方法MMutex,所以不应该出错......我想(哼)。

答案 3 :(得分:0)

如果您可以更改库实现,则可以每次调用其中一个库的函数来访问首次使用时创建的单例。

或者将全局/静态变量放入库中,在构造期间将其初始化并在销毁期间将其关闭。 (如果库本身使用全局变量并且初始化/关闭的顺序与它们冲突,那可能会很烦人。而且,链接器可能决定消除未引用的全局变量......)

否则,我看不出你想如何避免引用计数。 (但请注意,它的缺点是可能在程序的生命周期内创建多个初始化/关闭循环。)

答案 4 :(得分:0)

如果您的C库例程集不是太大,您可以尝试组合SingletonFacade模式,以便仅通过Facade调用C库例程。 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