2017-06-25 21 views
8

tôi có như sau (giản thể) mã trong dự án hiện tại của tôi:C++ lambda'this' con trỏ huỷ bỏ hiệu lực sau phẫu thuật di chuyển

#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; 
} 

Khi tôi chạy nó, giá trị 50 được in thay vì giá trị dự kiến ​​2. Tôi cho rằng điều này xảy ra bởi vì hàm lambda bắt con trỏ this hiện tại. Sau thao tác di chuyển, các thay đổi con trỏ this và chức năng ghi sai a.

Bây giờ câu hỏi của tôi là: Có cách nào để thay đổi tham chiếu đã chụp của lambda thành Test mới sao cho giá trị 2 được in không?

Trả lời

4

Giải pháp không được chụp this. Thay vào đó, hãy thay đổi loại hàm được capture của bạn để chấp nhận nó. Và sử dụng một con trỏ đến thành viên (được ghi theo giá trị) để truy cập gián tiếp vào 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


Như Galik ghi chú khác, nếu bạn chỉ cần truy cập vào một thành viên mã hóa cứng duy nhất, sau đó bạn thậm chí không cần điều đó con trỏ tới thành viên. Vì vậy, lambda có thể được chụp ít hơn:

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

Bạn không thể làm 't-> a = 2;' và quên con trỏ thành viên? – Galik

+0

@Galik - Tôi không biết tại sao, nhưng tôi có ấn tượng rằng OP muốn thành viên không bị mã hóa. Tôi sẽ thêm rằng trong khóa học, kể từ khi một lambda nắm bắt ít thậm chí còn đơn giản như bạn đã lưu ý. – StoryTeller

+0

Dường như với tôi vấn đề cơ bản là lambda bắt con trỏ 'this' mà không được cập nhật với * di chuyển *. Bằng cách truyền con trỏ 'this' hiện tại làm tham số, lambda luôn hoạt động trên đối tượng chính xác. – Galik

Các vấn đề liên quan