我问这个问题的一般编码指南:
class A {
A() { ... throw 0; }
};
A obj; // <---global
int main()
{
}
如果obj
在上面的代码中抛出异常,那么它最终会在调用main()
之前终止代码。所以我的问题是,我应该为这种情况采取什么指导方针?是否可以为这些类声明全局对象?我应该总是不要自己这样做,还是一开始就抓住错误的好倾向?
答案 0 :(得分:4)
如果你需要一个构造函数可以抛出的对象的全局实例,你可以将变量设为静态,而不是:
A * f(){
try {
//lock(mutex); -> as Praetorian points out
static A a;
//unlock(mutex);
return &a;
}
catch (...){
return NULL;
}
}
int main() {
A * a = f(); //f() can be called whenever you need to access the global
}
这可以缓解由于过早的异常引起的问题。
编辑:当然,在这种情况下,解决方案是单身人士的90%。通过将f()
移至A
?
答案 1 :(得分:1)
不,你不应该将这些对象声明为全局 - 任何异常都将无法处理并且很难诊断。该程序将崩溃,这意味着它将具有非常差(低于零)的用户体验,并且将难以维护。
答案 2 :(得分:0)
正如@Kerrek SB在评论中提到的,答案取决于可能导致你的课程抛出的原因。如果您正在尝试获取可能不可用的系统资源,我觉得您不应该声明全局对象。一旦用户尝试运行它,您的程序就会崩溃;不用说,这看起来不太好。如果它可以抛出std::bad_alloc
或某种在正常情况下不太可能发生的异常(假设您没有尝试分配几GB内存),那么可以创建一个全局实例;但是,我仍然不会这样做。
相反,您可以声明一个指向该对象的全局指针,在main
开始时(在生成任何线程之前等)实例化该对象,并将指针指向此实例,然后通过指针。这使您的程序有机会处理异常,并可能提示用户采取某种补救措施(例如弹出重试按钮以尝试重新获取资源)。
答案 3 :(得分:0)
声明一个全局对象很好,但是你的类的设计是微不足道的,它缺乏与实际需求和使用兼容的细节。
答案 4 :(得分:0)
似乎没有人提到的一个解决方案是使用函数try 块。基本上,如果情况是没有构造 对象,你的程序的其余部分将无法工作或能够做任何事情 有用,那么唯一真正的问题是你的用户会得到一些排序 如果构造函数以a终止,则出现难以理解的错误消息 例外。所以你将构造函数包装在函数try块中,并且 生成一个可理解的消息,然后返回错误:
A::() try
: var1( initVar1 )
// ...
{
// Additional initialization code...
} catch ( std::exception const& ) {
std::cerr << "..." << std::endl;
exit(EXIT_FAILURE);
} catch (...) {
std::cerr << "Unknown error initializing A" << std::endl;
exit(EXIT_FAILURE);
}
此解决方案实际上只适用于所有实例 对象是静态声明的,或者如果您可以隔离单个对象 静态实例的构造函数;对于非静态实例,它 传播异常可能更好。
答案 5 :(得分:0)
就像@J T所说,你可以这样写:
struct S {
S() noexcept(false);
};
S &globalS() {
try {
static S s;
return s;
} catch (...) {
// Handle error, perhaps by logging it and gracefully terminating the application.
}
// Unreachable.
}
这种情况非常严重,请阅读ERR58-CPP. Handle all exceptions thrown before main() begins executing了解更多详情。