2014-12-08 4 views
1

코드를 여전히 문제가있는 가장 작은 샘플로 단순화했습니다. 이 코드는 "42"를 인쇄해야하지만 대신 다른 번호를 인쇄합니다. 또한 소멸자에서 "Secret"개체의 주소를 인쇄하고 액세스 할 때 너무 일찍 소멸되었음을 보여줍니다. 내가 여기서 뭔가 잘못하고있는 중이거나 컴파일러에 문제가있을 수 있습니까?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 (우분투 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' 람다에서와 같이 암시 적으로조차하지 않습니다). 그 람다를 복사하는 것은 캡쳐 된 포인터를 복사하는데, 즉 얕은 복사를 수행한다. – dyp

+0

'auto output = [this]() {'이 줄은 문제가있는 것처럼 보입니다. 포인터 대신'* this'를 복사하고 싶습니다. –

+1

@BryanChen 정확히 내가 생각한 것 : http://coliru.stacked-crooked.com/a/43b70f00c4a20469 – dyp

답변

3

캡쳐 this 캡처와 포인터 의미. 이 변경이 행

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

문제를 해결

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

라인 : makeSecretPrinter().run() 것은 실제로 makeSecretPrinter() 먼저 실행하고 실행 run(). 그러나 run()이 실행 중일 때는 이미 makeSecretPrinter() 범위를 벗어났습니다. 따라서 람다 함수는 호출 할 매개 변수로서 올바른 값을 얻지 못합니다.

클래스가 함수 포인터 만 받거나 함수 참조 인 경우 의미가 같습니다. 즉,이 값은 Copier 클래스로 전달되지 않습니다. Copier이 'run()'을 시도하면 makeSecretPrinter()에 변수를 가져와야합니다. 그러나, 내가 말했듯이 'run()'이 실행될 때 범위를 벗어납니다.

관련 문제