std :: transformを並列実行ポリシーで使用できますか?


11

間違えなければ 、入出力イテレータと同じ範囲を使ってその場でstd::transform実行せることができます。私がいくつかのstd::vectorオブジェクトを持っていると仮定してvec、私は書くでしょう

std::transform(vec.cbegin(),vec.cend(),vec.begin(),unary_op)

適切な単項演算を使用しますunary_op

C ++ 17標準を使用しstd::execution::parて、最初の引数としてinを付けて、変換を並列実行したいと思います。これにより、関数がのcppreference記事のstd::transformオーバーロード(1)から(2)に変わります。ただし、このオーバーロードへのコメントは次のように述べています。

unary_op[...]終了反復子を含むすべての反復子を無効にしたり、関係する範囲の要素を変更したりしてはなりません。(C ++ 11以降)

「要素を変更する」とは、実際にアルゴリズムを使用できないことを意味しますか、それとも、誤って解釈した別の詳細について話しているのですか?

回答:


4

ここで標準を引用するには

[alg.transform.1]

op [...]はイテレータまたはサブ範囲を無効にしたり、範囲内の要素を変更したりしてはなりません

これはunary_op、引数として指定された値またはコンテナ自体のいずれかを変更することを禁止します。

auto unary_op = [](auto& value) 
{ 
    value = 10;    // this is bad
    return value;
}

auto unary_op = [&vec](auto const& value) 
{ 
    vec[0] = value;   // also bad
    return value;
}

auto unary_op = [&vec](auto& value) 
{ 
    vec.erase(vec.begin());   // nope 
    return value;
}

ただし、次は問題ありません。

auto unary_op = [](auto& value)  // const/ref not strictly needed
{         
    return value + 10;   // totally fine
}

auto unary_op = [&vec](auto& value)
{         
    return value + vec[0];   // ok in sequential but not in parallel execution
}

UnaryOperation私たちから独立しています

[alg.transform.5]

単項変換[...]の場合、結果は最初に等しい場合があります。

インプレース操作が明示的に許可されていることを意味します。

[algorithms.parallel.overloads.2]

特に明記されていない限り、ExecutionPolicyアルゴリズムのオーバーロードのセマンティクスは、オーバーロードなしのオーバーロードと同じです。

実行ポリシーには、アルゴリズム上でユーザーに表示される違いはありません。このアルゴリズムでは、実行ポリシーを指定しない場合とまったく同じ結果が得られることが期待できます。


6

私はそれが別の細部について話していると信じています。unary_op配列の要素を取り、値を返します。その値はtransform宛先シーケンスに(によって)保存されます。

だからこれunary_opは結構です:

int times2(int v) { return 2*v; }

しかし、これはそうしません:

int times2(int &v) { return v*=2; }

しかし、それはあなたが本当に求めていることではありません。のunary_opバージョンをtransform同じ送信元と宛先の範囲を持つ並列アルゴリズムとして使用できるかどうかを知りたい。なぜかわかりません。transformソースシーケンスの単一の要素を宛先シーケンスの単一の要素にマップします。ただし、unary_op実際に単項でない場合(つまり、シーケンスの他の要素を参照している場合-要素を読み取るだけでも、データの競合が発生します)。


1

引用したリンクの例でわかるように、要素を変更しても、要素のすべてのタイプの変更を意味するわけではありません

関数のシグネチャは次と同等である必要があります。

Ret fun(const Type &a);

これには、要素の変更が含まれます。あなたが先に同じイテレータを使用する場合、最悪のケースでは、変更は、例えばaはイテレータの無効化発生することはありませんpush_backベクター又はへerasのINGのvectorでしょうイテレータの無効化の原因となります。

あなたがライブをすべきでない失敗の例を見てください。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.