10

次のプログラムは、VS11 ベータ版、gcc 4.5、または clang 3.1 ではビルドされません。

#include <thread>
#include <memory>

int main() {
    std::unique_ptr<int> p;
    std::thread th([](std::unique_ptr<int>) {

    },std::move(p));
    th.join();
}

これは、引数の型がコピー可能ではないためですが、実装はそれをコピーしようとします。

私が知る限り、このプログラムは適切に構成されており、機能するはずです。std::thread の要件は、移動可能でコピー不可能な引数がここで機能することを暗示しているようです。具体的には、呼び出し可能なオブジェクトと各引数が MoveConstructible の要件を満たし、INVOKE(DECAY_COPY(std::forward<F>(f)),DECAY_COPY(std::forward<Args>(args))...)有効な式である必要があることを示しています。

この場合、式は次のように機能すると思います。

template <class T> typename std::decay<T>::type decay_copy(T&& v)
{ return std::forward<T>(v); }

std::unique_ptr<int> p;
auto f = [](std::unique_ptr<int>) {};

decay_copy(f)(decay_copy(std::move(p)));

そして、これは のコピーを含むべきではないと思いますp。gcc は少なくともこの式をコンパイルできますが、VS11 はコンパイルできません。

  1. 要件について間違っていますか?引数はコピー可能でなければなりませんか?
  2. 標準は、実装が引数をコピーするために、この問題に余裕を残していますか?
  3. または、私が試した実装は準拠していませんか?
4

2 に答える 2

14

N3337 の 30.3.1.2、パラグラフ 3 および 4 から:

template <class F, class ...Args> explicit thread(F&& f, Args&&... args);

Requires :FのそれぞれTiが要件Argsを満たす必要がありMoveConstructibleます。INVOKE (DECAY_-COPY ( std::forward<F>(f)), DECAY_COPY (std::forward<Args>(args))...)(20.8.2) は有効な式でなければなりません。

効果: スレッド型のオブジェクトを構築します。実行の新しいスレッドは、構築スレッドで評価されるINVOKE (DECAY_-COPY ( std::forward<F>(f)), DECAY_COPY (std::forward<Args>(args))...)呼び出しで実行されます。DECAY_COPYこの呼び出しからの戻り値は無視されます。[ 注: これは、 のコピーの呼び出しからスローされなかった例外はf、新しいスレッドではなく、構築中のスレッドでスローされることを意味します。—終わりの注] の呼び出しがINVOKE (DECAY_COPY ( std::forward<F>(f)), DECAY_COPY (std::forward<Args>(args))...)キャッチされない例外で終了する場合、std::terminate が呼び出されます。

はい、これはうまくいくはずです。そうでない場合、それは実装のバグです。

パラメータの移動/コピーは新しいスレッドで行われることに注意してください。参照を別のスレッドに渡しているため、そのスレッドが開始されるまでそれらがまだ存在していることを確認する必要があります。

于 2012-04-03T21:47:10.803 に答える
3

別の方法として、また標準的なstd::threadイディオムとして、参照ラッパーを渡すことができます。

int p;
std::thread([](int & x) { /* ... */ }, std::ref(p));

std::reference_wrapper<int>これは、値のセマンティクスを持ち、 への参照をラップするタイプ のオブジェクトを作成しますint(つまり、ラッパーをコピーすると、参照がエイリアス化されます)。

于 2012-04-03T22:19:32.197 に答える