2013-06-27 59 views
2

我想註冊一個可能從其容器中移除的回調。但我發現捕獲的變量似乎被清理了。這樣的代碼:從lambda中的容器中刪除自己

class A { 
    int val_; 
public: 
    A(int val) : val_(val) {} 
    void foo() { 
     std::cout << val_ << std::endl; 
    } 
}; 

int main() 
{ 
    const int func_index = 1; 
    std::unordered_map<int, std::function<void(void)>> container; 
    A a(10); 
    container.insert(std::make_pair(func_index, [&container, func_index, &a]() { 
     container.erase(func_index); 
     for (int i = 0; i < 10; i++) { 
      a.foo(); 
     } 
    })); 
    container[func_index](); 
    return 0; 
} 

的解決方案,移動的std ::函數對象到拉姆達推遲其銷燬:

class A { 
    int val_; 
public: 
    A(int val) : val_(val) {} 
    void foo() { 
     std::cout << val_ << std::endl; 
    } 
}; 

int main() 
{ 
    const int func_index = 1; 
    std::unordered_map<int, std::function<void(void)>> container; 
    A a(10); 
    container.insert(std::make_pair(func_index, [&container, func_index, &a]() { 
     std::function<void(void)> self = std::move(container[func_index]); 
     container.erase(func_index); 
     for (int i = 0; i < 10; i++) { 
      a.foo(); 
     } 
    })); 
    container[func_index](); 
    return 0; 
} 
+3

你可能需要在這裏添加什麼像您期望實際上是不工作的一些更詳細。 – crowder

+0

你是什麼意思「我發現捕獲的變量似乎被清理」? –

回答

5

你的代碼是未定義的行爲,因爲你正在訪問將其從容器中刪除後關閉。你應該從容器後取出封做的工作吧:

class A { 
    int val_; 
public: 
    A(int val) : val_(val) {} 
    void foo() { 
     std::cout << val_ << std::endl; 
    } 
}; 

int main() 
{ 
    const int func_index = 1; 
    std::unordered_map<int, std::function<void(void)>> container; 
    A a(10); 
    container.insert(std::make_pair(func_index, [&container, func_index, &a]() { 
     for (int i = 0; i < 10; i++) { 
      a.foo(); 
     } 
     container.erase(func_index); 
    })); 
    container[func_index](); 
    return 0; 
} 
+0

+1好的趕上... – Tom

+0

謝謝!但是我必須在lambda的開頭加上'erase'。有沒有什麼辦法可以禁用從容器索引這個函數,直到我可以在lambda結尾刪除它? – QingYun

+1

@ user2134183:在調用'erase'之前,您始終可以將相關數據保存到局部變量中。重要的是在清除閉包後*不*訪問捕獲的變量。 – Mankarse