抛出构造函数的异常

我正在与同事讨论有关从构造函数中抛出异常的问题,并认为我希望得到一些反馈。

从设计的角度来看,可以从构造函数中抛出异常吗?

假设我在课堂上包装了一个posix互斥体,它看起来像这样:

class Mutex {
public:
  Mutex() {
    if (pthread_mutex_init(&mutex_, 0) != 0) {
      throw MutexInitException();
    }
  }

  ~Mutex() {
    pthread_mutex_destroy(&mutex_);
  }

  void lock() {
    if (pthread_mutex_lock(&mutex_) != 0) {
      throw MutexLockException();
    }
  }

  void unlock() {
    if (pthread_mutex_unlock(&mutex_) != 0) {
      throw MutexUnlockException();
    }
  }

private:
  pthread_mutex_t mutex_;
};

我的问题是,这是做这件事的标准方式吗? 因为如果pthread mutex_init调用失败,则互斥对象不可用,因此抛出异常可确保不会创建互斥锁。

我是否应该为Mutex类创建一个成员函数init并调用pthread mutex_init,其中将基于pthread mutex_init的返回返回一个bool? 这样我不必为这样的低级对象使用异常。


是的,从失败的构造函数中抛出异常是执行此操作的标准方法。 阅读关于处理失败的构造函数的更多信息。 有一个init()方法也可以,但每个创建互斥对象的人都必须记住init()必须被调用。 我觉得这违背了RAII原则。


如果您确实从构造函数中抛出异常,请记住,如果需要在构造函数初始值设定项列表中捕获该异常,则需要使用函数try / catch语法。

例如

func::func() : foo()
{
    try {...}
    catch (...) // will NOT catch exceptions thrown from foo constructor
    { ... }
}

func::func()
    try : foo() {...}
    catch (...) // will catch exceptions thrown from foo constructor
    { ... }

抛出异常是处理构造函数失败的最佳方式。 您应该特别避免半建构一个对象,然后依靠您的类的用户通过测试某种标志变量来检测构建失败。

在一个相关的问题上,你有几种不同的异常类型来处理互斥错误,这让我感到担忧。 继承是一个很好的工具,但它可以被过度使用。 在这种情况下,我可能会更喜欢单个MutexError异常,可能包含一条信息错误消息。

链接地址: http://www.djcxy.com/p/86825.html

上一篇: Throwing exceptions from constructors

下一篇: Strange program hang, what does this mean in debug?