3

失敗の可能性がある上から値をポップするための次の関数を使用して、ミューテックスで保護されたスタックを作成しています。

bool try_pop(T& value)
{
    std::lock_guard<std::mutex> lock(mutex_);
    if (ctr_.empty())
        return false;
    value = std::move(ctr_.back());
    ctr_.pop_back();
    return true;
}

std::vector基になるコンテナーとしてa を使用しています。コピー不可能な T をスタックに格納するために (例: std::unique_ptr) std::move、ベクターの後ろから T を削除していました。そうしないと、コピーが作成されます。2 つの質問: a) これは正しいですか? T は移動またはコピーされますか? b) 例外の安全性が心配です。移動がスローされた場合、スタックはポップされませんが、トップ値は半分移動された状態になる可能性があります。これは可能ですか、どうすれば解決できますか?

4

3 に答える 3

7

a) 移動コンストラクターがあると仮定して、移動されます。コピー コンストラクターを定義しているがムーブ コンストラクターを定義していない型の場合は、コピーされます。

b) 強力な例外保証が必要な場合は、入力が移動コンストラクターstd::move_if_noexceptを提供する場合にのみ移動を有効にする whichを使用する必要があります。noexcept()そのようにして、移動コンストラクターがスローできる場合、コピーを作成することに頼るので、例外がスローされた場合、オブジェクトはスタック上で変更されないままになります。 std::move_if_noexceptこのような場合に強力な保証を提供するために明示的に提供されました。

編集: Howard Hinnant が指摘しているように、現在のコード例は移動の構築ではなく移動の代入を使用しているため、希望どおりに動作しstd::move_if_noexceptない可能性があります。割り当てを使用しているときにそれを解決するには、以下に基づく独自のラッパーを作成する必要がありますstd::move_if_noexcept

template <class T> typename std::conditional<
!std::is_nothrow_move_assignable<T>::value && std::is_copy_assignable<T>::value,
const T&, T&&>::type move_if_assign_noexcept(T& x) noexcept {
   return std::move(x);
}
于 2012-10-31T11:50:46.290 に答える
3

それは正しく(例外安全性全体を除いて)、移動されます(移動をサポートしている場合)。

あなたが発見したように、移動がスローされる可能性がある場合、強力な例外保証を提供することは不可能です。その場合、コピーに頼る必要があります。ただ、投げ技はめったにないのであまり考えない。

于 2012-10-31T11:44:11.153 に答える
2

1) unique_ptrc-tor が移動したため、移動されます。

2)

n3337 20.7.1.2 から

unique_ptr(unique_ptr&& u) noexcept;
unique_ptr& operator=(unique_ptr&& u) noexcept;
于 2012-10-31T11:46:21.490 に答える