2017-06-25 14 views
8

後、私は私の現在のプロジェクトの次の(簡体字)のコードを有する:C++ラムダ'this'ポインタ無効移動操作

#include <iostream> 
#include <string> 
#include <functional> 
#include <vector> 


class Test{ 

public: 

    Test() = default; 
    Test(const Test& other) = delete; 
    Test& operator=(const Test& other) = delete; 
    Test(Test&& other) = default; 
    Test& operator=(Test&& other) = default; 



    void setFunction(){ 
     lambda = [this](){ 
      a = 2; 
     }; 
    } 

    int callAndReturn(){ 
     lambda(); 
     return a; 
    } 

private: 
    std::function<void()> lambda; 
    int a = 50; 
}; 


int main() 
{ 
    Test t; 
    t.setFunction(); 
    std::vector<Test> elements; 
    elements.push_back(std::move(t)); 
    std::cout << elements[0].callAndReturn() << std::endl; 
} 

を私はそれを実行すると、値50の代わりに期待値2で印刷されています。これは、ラムダ関数が現在のthisポインタを取得しているためです。移動操作後、thisポインターが変更され、関数は間違ったaに書き込みます。

私の質問はラムダのキャプチャされたリファレンスを新しいTestに変更して、値2を表示する方法はありますか?

答えて

4

解決策は、thisを全くキャプチャしません。代わりに、キャプチャした関数タイプを受け入れて変更します。そして、aへの間接アクセスのためのメンバーへのポインタ(値によって取り込まれる)を使用してください。

std::function<void(Test*)> lambda; 

void setFunction(){ 
    auto a = &Test::a; 
    lambda = [=](Test *t){ 
     (t->*a) = 2; 
    }; 
} 

int callAndReturn(){ 
    lambda(this); 
    return a; 
} 

Live Example


Galikが指摘したように、あなただけ、あなたもメンバーへのポインタを必要としない、単一のハードコーディングされたメンバーにアクセスする必要がある場合。したがって、ラムダはキャプチャレスである可能性があります。

void setFunction(){ 
    lambda = [](Test *t){ 
     t->a = 2; 
    }; 
} 
+2

't-> a = 2;'を実行してメンバポインタを忘れることはできませんか? – Galik

+0

@Galik - 理由はわかりませんが、OPがメンバーにハードコードされないようにしたいという印象を受けました。キャプチャレスラムダは、あなたが指摘したようにもっと簡単なので、私はもちろんそれを追加します。 – StoryTeller

+0

基本的な問題は、* move *で更新されない 'this'ポインタをキャプチャしているラムダです。現在の 'this'ポインタをパラメータとして渡すことで、ラムダは常に正しいオブジェクトで動作します。 – Galik

関連する問題