如果构造函数抛出异常,那么拥有该类的全局对象是否有意义?

时间:2011-08-08 15:04:13

标签: c++ exception global-variables coding-style

我问这个问题的一般编码指南:

class A {
  A() { ... throw 0; }
};
A obj;  // <---global

int main()
{
}

如果obj在上面的代码中抛出异常,那么它最终会在调用main()之前终止代码。所以我的问题是,我应该为这种情况采取什么指导方针?是否可以为这些类声明全局对象?我应该总是不要自己这样做,还是一开始就抓住错误的好倾向?

6 个答案:

答案 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了解更多详情。