是否有一种模式可用于调用底层(C)库的必需初始化和清理例程?在我的例子中,我想创建包装类,以便它可以组成其他对象。问题是,当我销毁包装类时,会调用底层库的清理例程。这很好,直到我实例化我的包装类的多个对象。我的问题是什么是最佳方式来真正处理这种情况?我想到了静态参考计数器,但我想知道是否还有其他可能更好的选择和涉及的交易。
答案 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
已正确初始化(一次)并且直到不再需要它为止。
Boost
为once issue提供了设施,因为我们使用基于堆栈的方法MMutex
,所以不应该出错......我想(哼)。
答案 3 :(得分:0)
如果您可以更改库实现,则可以每次调用其中一个库的函数来访问首次使用时创建的单例。
或者将全局/静态变量放入库中,在构造期间将其初始化并在销毁期间将其关闭。 (如果库本身使用全局变量并且初始化/关闭的顺序与它们冲突,那可能会很烦人。而且,链接器可能决定消除未引用的全局变量......)
否则,我看不出你想如何避免引用计数。 (但请注意,它的缺点是可能在程序的生命周期内创建多个初始化/关闭循环。)
答案 4 :(得分:0)
如果您的C库例程集不是太大,您可以尝试组合Singleton和Facade模式,以便仅通过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