假设我有一个C库,它有自己的(de)初始化例程,就像其中许多例程一样。
init_API();
deinit_API();
现在假设我想为用户提供另一层抽象,并使用静态实例化的类抽象掉这些调用。我想的方法是:
struct API_initializer{
API_initializer(){
init_API();
if(API_init_failure)
throw (APIFailureException); //important
}
~API_initializer(){
deinit_API();
}
};
struct API_initializer_holder{
static API_initializer initializer;
};
现在,我的问题是,这是明确定义的行为吗? I.E.,是否会在某个合理的点上调用静态构造函数,并且C API的所有(静态)变量是否需要正确初始化?另外,抛出用户无法捕获的异常是不好的做法吗?
答案 0 :(得分:3)
根据我的经验,尝试依赖静态初始化顺序是个坏主意。
更好的想法是摆脱持有者,然后去:
int main()
{
API_initializer foo;
// rest of program
}
如果你真的希望它失败,那么请包含一个try..catch块。
NB。使课程不可复制,以防止意外。
答案 1 :(得分:2)
不,如果初始化失败,程序将中断。您无法捕获异常并处理它,因为全局变量(静态成员数据)在main()
之前初始化。
最好在init_API()
中致电deinit_API()
和main()
。
答案 2 :(得分:1)
标准的§3.6.2[basic.start.init] / p4-6涵盖了这一点:
它是实现定义的动态初始化 具有静态存储持续时间的非局部变量在之前完成
main
的第一个陈述。如果初始化推迟到某些 在主要的第一个陈述之后的时间点,它应该在之前发生 第一次使用同一个中定义的函数或变量 翻译单位作为要初始化的变量。 35[...]
如果通过异常退出具有静态或线程存储持续时间的非局部变量,则会调用
std::terminate
。35 具有静态存储持续时间且具有副作用的初始化的非局部变量必须初始化,即使它没有被使用过。
由于您的静态对象无法与您正在包装的C库中的函数位于同一个转换单元中,因此保证初始化的唯一方法是在与main()
相同的转换单元中定义它,这并没有让我觉得为最终用户增添了任何便利。
无论如何,如果初始化失败,通过抛出异常来调用std::terminate
可能不是一个好主意。最终用户可能希望做更好的错误处理。
答案 3 :(得分:0)
答案是:这取决于。如果实现了外部API
在C中(这样它就没有动态初始化),它就是
没有在任何静态初始化器中使用(应该是
因为他们无法安全地做init_API
),
那个成语或多或少是安全的(除了你不应该这样)
允许异常从静态初始化程序中转义。是否
这是一个好主意或不是另一个问题;如果
初始化可能会失败,您可能不希望以前执行它
你可以捕捉并处理错误,这意味着你已经进入了
main
。