2014-12-08 108 views
1

我簡化了代碼,使其仍然存在問題。此代碼應該打印「42」,而是打印一個不同的數字。我還在析構函數中打印了「祕密」對象的地址,並在訪問它時顯示它已被破壞得太早。我在這裏做錯了什麼,或者這可能是編譯器的問題?C++析構函數太早調用

代碼:

#include <iostream>  

using namespace std;  

struct Secret{ 
    int value; 
    Secret(int value):value(value){} 
    ~Secret(){ 
     cout<<"destructor:"<<(void*)this<<endl; 
     value=0; 
    } 
};  

template<class Func> 
class Copier{ 
public: 
    Func func; 
    Copier(Func func):func(func){} 
    void run(){ 
     func(); 
    } 
    auto copy(){ 
     auto output = [this](){ 
      func(); 
     }; 
     Copier<decltype(output)> out(output); 
     return out; 
    }  

}; 
auto makeSecretPrinter(){ 
    Secret secret(42); 
    auto secretPrinter = [secret](){ 
     cout<<"reading object at address:"<<(void*)&secret<<endl; 
     cout<<"the secret is:"<<secret.value<<endl; 
    }; 
    return Copier<decltype(secretPrinter)>(secretPrinter).copy(); 
}  

int main(){ 
    makeSecretPrinter().run(); 
    return 0; 
} 

鐺(版本3.5-1ubuntu1)輸出:

destructor:0x7fff9e3f9940 
destructor:0x7fff9e3f9938 
destructor:0x7fff9e3f9948 
destructor:0x7fff9e3f9950 
reading object at address:0x7fff9e3f9940 
the secret is:0 

GCC(Ubuntu的4.9.2-0ubuntu1〜14.04)4.9.2輸出:

destructor:0x7fff374facc0 
destructor:0x7fff374facb0 
destructor:0x7fff374faca0 
destructor:0x7fff374fac90 
reading object at address:0x7fff374facc0 
the secret is:-1711045632 
+0

捕獲'this'意味着用指針語義捕獲。如果捕獲的對象被銷燬,那麼你可能不會取消引用該指針(甚至不會隱式地執行,就像'copy'的'output' lambda中所做的那樣)。複製該lambda複製捕獲的指針,即執行淺拷貝。 – dyp 2014-12-08 02:21:31

+0

'auto output = [this](){'這條線似乎是問題所在。你真的想複製'* this'而不是一個指針 – 2014-12-08 02:22:30

+1

@BryanChen正是我想的:http://coliru.stacked-crooked.com/a/43b70f00c4a20469 – dyp 2014-12-08 02:23:36

回答

3

捕獲this捕獲指針語義。更改此:

auto output = [this](){ 
    func(); 
}; 

到這能解決問題:

auto output = [self=*this](){ 
    self.func(); 
}; 
0

行:makeSecretPrinter().run(),它實際執行makeSecretPrinter()第一,然後執行run()。但是,run()正在執行時,它已經超出makeSecretPrinter()的範圍。因此,lambda函數沒有得到正確的值作爲要調用的參數。

請注意,您的類只接收函數指針(或函數引用,它們在語義上相同)。這意味着該值不會傳遞到Copier類。當Copier嘗試'運行()'時,它需要拾取makeSecretPrinter()中的變量。但是,正如我所說的,當'run()'被執行時,它超出了範圍。