16

このようなコードは、r値参照の記事でよく見られます。

Dave Abrams:右辺値参照で移動

void g(X);

void f()
{
    X b;
    g(b);              // still need the value of b
    …
    g( std::move(b) ); // all done with b now; grant permission to move
}

コンパイラはこの最適化を自動的に生成できますか?つまり、l値を検出するためにとにかく破壊されてから移動される可能性がありますか、または一般的なケースでコンパイラがどのようにXクラスに実装された移動、コピー、または破棄?

そのような最適化が許可されている場合、それは実際にいくつかのコンパイラによって実行されますか?

4

3 に答える 3

12

いいえ。考慮してください:

using X = std::shared_ptr<int>;
void g(X);
void f() {
    X b = std::make_shared<int>();
    int &i = *b;
    g(b);              // last use of 'b'
    i = 5;
}

X一般に、コンパイラは、のコピー、移動、およびデストラクタのセマンティクスの変更が、の使用を取り巻くすべてのコードb(つまり、、の全体fgおよびそこで使用されるすべてのタイプ)の分析を実行せずに、正当な変更になると想定することはできません。

実際、場合によっては、プログラム全体の分析が必要になることがあります。

using X = std::shared_ptr<std::lock_guard<std::mutex>>;
std::mutex i_mutex;
int i;
void g(X);
void f() {
    X b = std::make_shared<std::lock_guard<std::mutex>>(i_mutex);
    g(b);              // last use of 'b'
    i = 5;
}

が移動されると、アクセスを使用bに同期する他のスレッドとのデータ競合が発生します。ii_mutex

于 2013-03-13T14:07:20.110 に答える
4

(...)一般的なケースを想定すると、コンパイラはXクラスにどのように移動、コピー、または破棄が実装されているかについて何も知りませんか?

いいえ、コンパイラは信仰に基づいて最適化を行うことは許可されていません。

明確にするために、この質問はコピーの省略とは関係ありません。コンパイラーはコピーを削除することを許可される場合がありますが、コピーを自由に移動するように変更することはできません。

于 2013-03-13T14:00:22.830 に答える
4

コンパイラはそれを行うことができますか?明示的な言語拡張としてのみ。標準では、それなしでそのような最適化を行うことは許可されていないためです。

彼らはそれをすべきですか?いいえ。の意味は、とg(b)の定義に基づいている必要がgありbます。暗黙的に変換できるgものを受け取るオーバーロードを持つ呼び出し可能な型である必要があります。b使用可能なすべてのの定義との定義へのアクセスが与えられればg、どの関数が呼び出されるかを正確bに決定できるはずです。

この「最適化」を許可するということは、これが不可能であることを意味します。関数内の正確な場所によっては、移動を実行する場合と実行しない場合がg(b) ありg(b)ます。それは良いことではありません。

returnそれを回避することは許可されていますが、それはまだ同じ意味を持っているからです。関数のスコープに存続期間が制限されている値型である場合は、return b常に移動を試みます。bb

于 2013-03-13T14:05:27.497 に答える