2017-02-09 77 views
5

我想實現用C++這塊高階功能的蟒蛇:不同的結果C++ 14

def add1(x): 
    def helper(): 
     nonlocal x 
     x += 1 
     return x 
    return helper 

這裏有三個版本我創建:

#include <iostream> 
#include <functional> 

using namespace std; 

function<int(void)> add1_v1(int x) { 
    function<int(void)> g = [&x]() {return ++x;}; 
    return g; 
} 

auto add1_v2(int x) { 
    function<int(void)> g = [&x]() {return ++x;}; 
    return g; 
} 

auto add1_v3(int x) { 
    auto g = [&x]() {return ++x;}; 
    return g; 
} 

int main() { 
    auto a = add1_v1(100); 
    auto b = add1_v2(100); 
    auto c = add1_v3(100); 
    for(int i = 0; i < 3; ++i) { 
     cout << a() << endl; 
    } 
    cout << "-------------------------------------------" << endl; 
    for(int i = 0; i < 3; ++i) { 
     cout << b() << endl; 
    } 
    cout << "-------------------------------------------" << endl; 
    for(int i = 0; i < 3; ++i) { 
     cout << c() << endl; 
    } 
    return 0; 
} 

輸出爲:

101 
102 
103 
------------------------------------------- 
4239465 
4239466 
4239467 
------------------------------------------- 
4201325 
4201325 
4201325 

只有add1_v1匹配我想要的東西。任何人都可以解釋我的理由嗎?

+0

什麼是「不工作」是什麼意思? – Brian

+0

@Brian修改了這個問題。 –

+0

他們都錯了。 'add1_v1'很幸運。 – immibis

回答

7

原因是這是未定義的行爲。

內部lambda通過引用捕獲x

問題是,只要add()返回,它的參數就會被銷燬,並且返回的lambda具有對被銷燬對象的懸掛引用。

該lambda必須按值捕獲x;什麼在我看來你真的想在這裏做的是一個mutable lambda

auto add(int x) { 
    function<int(void)> g = [x]() mutable {return ++x;}; 
    return g; 
} 

注意,這種方法帶有一定的影響,當涉及到隨後複製返回拉姆達;但只要返回的lambda仍然「在一個地方」,在其整個剩餘的生命週期內,所產生的語義可能就是您所期望的。

+1

'auto long_live_x = make_shared (x); return [=](){return ++ * long_live_x;};'也是可能的,有不同的折衷。 – ephemient

4

他們都是病態的,因爲你在拉姆達參考捕捉x,但x是一個局部變量,會被摧毀時擺脫功能add,則引用變得吊着,提領就可以了後者會導致UB,這意味着任何事情都是可能的;即使是第一個案件似乎工作正常。

0

不是一個答案,似乎功能所有版本的效果很好,如果你更改參數簽名add1_v *(INT & & X)