除此之外,在你的特定情况下,你不需要从构造函数中抛出,因为如果你的互斥量没有初始化,pthread_mutex_lock实际上会返回一个EINVAL,你可以在调用lock后抛出,就像在std::mutex中所做的那样:
void
lock()
{
int __e = __gthread_mutex_lock(&_M_mutex);
// EINVAL, EAGAIN, EBUSY, EINVAL, EDEADLK(may)
if (__e)
__throw_system_error(__e);
}
那么一般来说,对于构造过程中的获取错误,从构造函数抛出是可以的,并且符合RAII(资源获取即初始化)编程范式。
在RAII上检查这个例子
void write_to_file (const std::string & message) {
// mutex to protect file access (shared across threads)
static std::mutex mutex;
// lock mutex before accessing file
std::lock_guard<std::mutex> lock(mutex);
// try to open file
std::ofstream file("example.txt");
if (!file.is_open())
throw std::runtime_error("unable to open file");
// write message to file
file << message << std::endl;
// file will be closed 1st when leaving scope (regardless of exception)
// mutex will be unlocked 2nd (from lock destructor) when leaving
// scope (regardless of exception)
}
关注这些陈述:
静态标准::互斥锁
std::lock_guard<std::mutex> lock(mutex);
std::ofstream file(“example.txt”);
第一个陈述是RAII和noexcept。在(2)中很明显,RAII应用于lock_guard,它实际上可以抛出,而在(3)ofstream中似乎不是RAII,因为对象的状态必须通过调用is_open()来检查failbit标志。
乍一看,似乎还没有决定它的标准方式是什么,在第一种情况下std::mutex不抛出初始化,*与OP实现相比*。在第二种情况下,它将抛出std::mutex::lock中抛出的任何东西,而在第三种情况下,根本不抛出任何东西。
注意区别:
(1)可以被声明为静态的,并且实际上将被声明为一个成员变量
(2)实际上永远不会被声明为成员变量
(3)期望被声明为成员变量,并且底层资源可能并不总是可用的。
所有这些形式都是RAII;要解决这个问题,必须分析RAII。
资源:你的对象
获取(分配):正在创建的对象
初始化:你的对象处于不变状态
这并不需要初始化和连接构造中的所有内容。例如,当您要创建一个网络客户端对象时,您不会在创建时将其实际连接到服务器,因为这是一个缓慢的操作,会失败。相反,您可以编写一个connect函数来完成该任务。另一方面,您可以创建缓冲区或仅设置其状态。
Therefore, your issue boils down to defining your initial state. If in your case your initial state is mutex must be initialized then you should throw from the constructor. In contrast it is just fine not to initialize then ( as is done in std::mutex ), and define your invariant state as mutex is created . At any rate the invariant is not compromized necessarily by the state of its member object, since the mutex_ object mutates between locked and unlocked through the Mutex public methods Mutex::lock() and Mutex::unlock().
class Mutex {
private:
int e;
pthread_mutex_t mutex_;
public:
Mutex(): e(0) {
e = pthread_mutex_init(&mutex_);
}
void lock() {
e = pthread_mutex_lock(&mutex_);
if( e == EINVAL )
{
throw MutexInitException();
}
else (e ) {
throw MutexLockException();
}
}
// ... the rest of your class
};