2010-12-13 5 views
16

ラムダ関数を使用する場合は、変数([=]表記)をコピーすることを決定したとします。その変数をもう一度参照しない場合、コンパイラは結果の関数オブジェクトにその変数を移動できますか?ラムダで移動する

編集:たとえば、スレッド間でコールを移動するスニペットを作成しました。これを行うサンプルがあります。

extern "C" __declspec(dllexport) void parser_file_updated(Parser* p, const char* filename, int offset, int added) { 
    std::string file(filename); 
    p->make_call([=]() { 
     p->file_updated(std::move(file), offset, added); 
    }); 
} 

しかし明確に、ファイル変数は、ラムダdefinition-過ぎて生きるために、実際、ラムダは一度だけ呼ばれる必要はありませんが、私はコピーを移動しました。

+3

私は、これは一般的にコンパイラでは分かりづらいと思います。サンプルコードを提供できますか? – fredoverflow

+0

もちろん、「あたかも同じ」ルールがあります。しかし、私はあなたがコピーctorや移動ctorが副作用を持っているケースを考えていると思いますので、違いを知ることができます。興味深い質問。 – aschepler

+0

@aschepler:正しく呼び出すと、コンパイラーはコピーコンストラクターと移動コンストラクターの副作用を無視できます。 @DeadMG:それは最適化されているように私に見える、あなたはそれを試してみましたか? –

答えて

12

この変数をもう一度参照しない場合、コンパイラはそれを結果の関数オブジェクトに移動できますか?

コンパイラーがコピーをムーブに置き換えることができる唯一の状況は、コピーエリミッションを実行できるのとまったく同じ状況です。これらの状況には、ローカルオブジェクトを値で返すか、または一時的にオブジェクトを初期化することが含まれます。このような場合、コンパイラはソースを作成して同じオブジェクトをターゲットにしてコピーを削除することができます。何らかの理由でコンパイラがそれを行うことができない場合は、ターゲットオブジェクトの適切なコンストラクタを選択するためのオーバーロード解決に関して、ソースオブジェクトを評価値として考慮する必要があります。ただし、あなたの場合、ファイルはLvalueであり、上のケースのどれも適用されません。あなたは明示的な動きを使わなければなりません。

残念ながら、C++ 11には「移動キャプチャ」の構文はありません。 IMHO、それは残念です。しかし、std :: bindはこれをサポートしています。文字列が関数オブジェクトに移動するように

void foo(char const* p) { 
    string s = p; 
    auto fun = bind([](string const& s){ 
     ... 
    },move(s)); 
    fun(); 
} 

:このようなラムダ式ではstd ::バインドを組み合わせることが可能でなければなりません。

あなたが意図一度だけ、この関数を呼び出すと、再び関数オブジェクトの外に列を移動したい場合、あなたは非const参照を使用することができます。

void foo(char const* p) { 
    string s = p; 
    auto fun = bind([](string & s) { 
     some_other_func(move(s)); 
    },move(s)); 
    fun(); 
} 

注意あなたがない場合、そのここバインドを使用したいが、ラムダオブジェクトのコンストラクタは、Sのコピーを作成してみましょう、関数オブジェクトの外に列を移動すると、変更可能なキーワードが必要です。そうでない場合は閉鎖型の演算子()関数はconst-になりますので、

void foo(char const* p) { 
    string s = p; 
    auto fun = [=]() mutable { 
     //   ^^^^^^^ 
     some_other_func(move(s)); 
    }; 
    fun(); 
} 

を修飾されたものが順番にs const修飾された文字列。

C++では、ラムダキャプチャ節が少し柔軟になりました。現在

void foo(char const* p) { 
    string s = p; 
    auto fun = [s=move(s)]() mutable { // #1 
     some_other_func(move(s));  // #2 
    }; 
    fun(); 
} 

場所(some_other_funcが正確に宣言されている方法に応じて)ラムダオブジェクトと#2が移動に#1が移動文字列値を文字列値アウトを書き込むことができます。

+0

C++コンパイラは、観察可能な振る舞いが同じであれば、どのような最適化をも行うことができます。この特定のケースでは、あなたが話すことができなくてもオブジェクトを動かすことができるので、許可されます。これはあなたの答えを事実上間違ってしまいます。 – nwp

+0

@nwp:すべての目的と目的のために、私は同意しない。観察可能な振る舞いには、コピーctorか移動ctorが呼び出されたかどうかという事実が含まれます(関数が異なって振る舞うと仮定します)。もちろん、移動ctorの目的です。 as-ifルールは、ここでコストを削減するのに役立ちません。 – sellibitze

関連する問題