这"Idiom"定义明确吗?
Is This "Idiom" Well-Defined?
假设我有一个C库,它有自己的(反)初始化例程,就像许多库一样。
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;
};
现在,我的问题是,这是定义良好的行为吗?也就是说,静态构造函数是否会在某个合理的点被调用,以及C API是否需要正确初始化所有(静态)变量?此外,抛出用户无法捕获的异常是不好的做法吗?
根据我的经验,尝试依赖静态初始化顺序是一个坏主意。
一个更好的办法是去掉holder,直接输入:
int main()
{
API_initializer foo;
// rest of program
}
如果你真的想让它在失败时抛出,那么就包含一个try..catch块。
NB。将类设置为不可复制的,以防止发生意外。
不,如果初始化失败,程序将中断。您无法捕获异常并处理它,因为全局变量(静态成员数据)在main()
之前初始化。
最好在main()
中称init_API()
和deinit_API()
这是§3.6.2 [basic.start]所涵盖的。/p4-6的标准:
是由实现定义的具有静态存储持续时间的非局部变量在
main
的第一个语句。如果初始化延迟到第一次陈述后的时间点,应当发生在主语句之前第一次禁止使用在同一目录中定义的函数或变量翻译单元作为要初始化的变量35[…]
如果具有静态或线程存储时间的非局部变量的初始化通过异常退出,则调用
std::terminate
。35具有静态存储时间的非局部变量,如果初始化有副作用,即使它不被odr使用,也必须初始化。
因为你的静态对象不可能与你包装的C库中的函数在同一个翻译单元中,所以保证初始化的唯一方法是将它定义在与main()
相同的翻译单元中,这并没有给最终用户增加任何便利。
在任何情况下,如果初始化失败,通过抛出异常来调用std::terminate
可能不是一个好主意。最终用户可能希望做更好的错误处理。
答案是:视情况而定。如果实现了外部API(这样它就不会有动态初始化),而且它是不要在任何静态初始化器中使用(应该是在这种情况下,既然他们没有办法安全地做init_API
),那么这个习语或多或少是安全的(除了你不应该这样做)允许异常从静态初始化器转义。是否这是一个好主意还是不好是另一个问题;如果初始化可能失败,您可能不想之前执行它你可以捕获并处理这个错误,这意味着你成功了main
。
- 在提升multi_index容器中,是否定义了"default index"?
- #定义c-预处理器常量..我做错了什么
- 用C++中的一个变量定义一个常量
- 部分定义/别名模板模板参数
- C++映射:具有自定义类的运算符[]不起作用(总是返回0)
- #为""定义宏;静态";针对不同的上下文
- 如何确保C++函数在定义之前声明(如override关键字)
- 创建一个函数以在输入为负数或零时输出字符串.第一次执行用户定义的函数
- 当类在C++中定义时,有什么方法可以"register"类吗?
- 在命名空间中定义函数还是限定函数
- 此代码是否违反一个定义规则
- 编译C++时未定义的引用
- 不同翻译单元中不可重载的非内联函数定义
- 为什么在定义函数之前先声明它
- 有没有什么方法可以使用一个函数中定义的常量变量,也可以由c++中同一程序中的其他函数使用
- 在类定义之后定义一个私有方法
- 使用用户定义函数的字符串反转
- 用户定义函数中的指针和输入
- 是否可以在 C++03 中定义'move-and-swap idiom'等效项
- 这"Idiom"定义明确吗?