从构造函数中抛出异常

343

我正在和一位同事就从构造函数中抛出异常进行辩论,想要听取一些反馈意见。

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

比如说,我正在将一个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 的返回值返回一个布尔值?这样我就不必为这种低级对象使用异常了。

从构造函数中抛出异常和从任何其他函数中抛出一样,这是可以的。话虽如此,你应该在任何函数中小心地抛出异常。 - g24l
5
是否考虑移除你的锁定/解锁方法,直接在构造函数中锁定互斥量,在析构函数中解锁?这样,在作用域内简单地声明一个自动变量就会自动执行锁定/解锁操作,无需处理异常、返回等问题...请参见 std::lock_guard 的类似实现。 - Laurent Grégoire
除非它们非常简单且没有任何清理代码,否则你将会遭受到难以预料的打击。 - Andy Krouwel
2
@LaurentGrégoire:在构造函数中创建和锁定互斥量是没有意义的,因为没有其他人会引用该互斥量,所以它不会保护任何东西。你需要使用lockunlock,这样你的互斥类型才能与std::lock_guard一起工作;他正在重新实现std::mutex,而不是std::lock_guard,这就是C++标准库中这两个类分开的原因。 - ShadowRanger
@ShadowRanger 说得没错;但我这里假设他可以在类的构造函数中给出某种上下文来允许此重用(甚至使用全局共享互斥量)。无论如何,重新发明轮子并不是非常有用的。 - Laurent Grégoire
显示剩余2条评论
11个回答

-2

尽管我没有在专业水平上使用C++,但我认为从构造函数中抛出异常是可以的。如果需要,我会在.Net中这样做。请查看thisthis链接。也许你会感兴趣。


13
.NET 不是 C++,JAVA 也不是。它们抛出异常的机制不同,并且成本也不同。 - g24l

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接