"C++ Concurrency in Action"の本を読んでいて、スレッドセーフなデータ構造(スタックなど)で例外の安全性を理解しようとしています。競合状態を避けるために、著者の状態は、pop
は両方の操作を行う必要があります - しかし、ポップ、スタックから項目を返す:shared_ptrと例外の安全性を返す
場合スタックが変更された後にのみポップされた値が呼び出し元に返されますが、データをコピーして呼び出し元に返すプロセスで例外がスローされる可能性があります。ここで
解決策が提案されている。この場合
std::shared_ptr<T> pop()
{
std::lock_guard<std::mutex> lock(m);
if(data.empty()) throw runtime_error("empty");
std::shared_ptr<T> const res(std::make_shared<T>(data.top()));
data.pop();
return res;
}
我々はmake_shared
ライン上コピーコンストラクタの呼び出しを得ました。コピーコンストラクタが例外をスローすると、スタックはまだ変更されておらず、良好です。
私はそれがこのスニペットから多くをどのように異なるかを見ていないしかし:
T pop2() {
std::lock_guard<std::mutex> lock(m);
if(data.empty()) throw runtime_error("empty");
auto res = data.top();
data.pop();
return res;
}
ここでは、リターンにdata.top()
ラインでコピーコンストラクタ呼び出しと移動コンストラクタを持っています。繰り返しますが、コピーコンストラクタが例外をスローした場合、スタックはまだ変更されていないので、良いことです。 MoveContructorは例外をスローすることは想定されていません。
何か不足していますか? shared_ptr
を返すことのメリットはT
です。
移動コンストラクタはスローすることができます。 – Simple
本の私のPDFコピーには、 'throw runtime_error(" empty ")'の代わりに 'throw empty_stack()'があります。本の 'empty_stack'クラスは' std :: exception'から直接継承しています。あなたの質問の 'runtime_error'が' std :: runtime_error'である場合、 'throw runtime_error(" empty ");' [他の例外も同様に投げるかもしれません](https://stackoverflow.com/questions/36106747)/how-to-construct-a-stdexcept-exception-without-throwing)が含まれます。 – jotik
ええ、私も 'empty_stack'を持っています。この例では 'runtime_exception'と置き換えました。 – lstipakov