ミューテックスが初期化されていない場合は実際にEINVALを返し、の呼び出し後にスローできるため、特定のケースでコンストラクターからスローする必要がないという事実は別として、次のように実行されます。pthread_mutex_lock
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(Resource-acquisition-is-Initialization)プログラミングパラダイムに準拠しています。
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)
}
これらのステートメントに焦点を当てます。
static std::mutex mutex
std::lock_guard<std::mutex> lock(mutex);
std::ofstream file("example.txt");
最初のステートメントはRAIIとnoexcept
です。lock_guard
(2)では、RAIIが適用され、実際に適用できることは明らかですがthrow
、(3)では、フラグをofstream
チェックする呼び出しによってオブジェクトの状態をチェックする必要があるため、RAIIではないようです。is_open()
failbit
一見すると、それが標準的な方法であるかどうかは未定であり、最初のケースでstd::mutex
は、* OP実装とは対照的に*、初期化をスローしません。2番目のケースでは、からスローされたものはstd::mutex::lock
すべてスローされ、3番目のケースではスローはまったくありません。
違いに注意してください。
(1)静的に宣言でき、実際にはメンバー変数として宣言されます(2)実際にはメンバー変数として宣言されることは期待されません(3)メンバー変数として宣言されることが期待され、基になるリソースは常に利用できるとは限りません。
これらの形式はすべてRAIIです。これを解決するには、 RAIIを分析する必要があります。
- リソース:オブジェクト
- 取得(割り当て):作成中のオブジェクト
- 初期化:オブジェクトは不変状態にあります
これには、構築時にすべてを初期化して接続する必要はありません。たとえば、ネットワーククライアントオブジェクトを作成する場合、失敗を伴う低速操作であるため、作成時に実際にサーバーに接続することはありません。代わりに、connect
まさにそれを行う関数を記述します。一方、バッファを作成することも、単にその状態を設定することもできます。
したがって、問題は、初期状態の定義に要約されます。あなたの場合、初期状態がmutexである場合は、初期化する必要があり、コンストラクターからスローする必要があります。対照的に、(で行われているように)初期化せず、 mutexが作成されstd::mutex
たときに不変状態を定義するのは問題ありません。いずれにせよ、オブジェクトはパブリックメソッドとの間で変化するため、不変条件は必ずしもそのメンバーオブジェクトの状態によって損なわれるわけではありません。mutex_
locked
unlocked
Mutex
Mutex::lock()
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
};