c ++析构函数调用得太早了

时间:2014-12-08 02:18:59

标签: c++ gcc c++14 clang++

我已经将代码简化为仍然存在问题的最小样本。此代码应打印" 42",而是打印不同的数字。我还打印了#34; Secret"的地址。析构函数中的对象,当访问它时,表明它被过早地破坏了。我在这里做错了什么,或者这可能是编译器的问题?

代码:

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

clang(版本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

2 个答案:

答案 0 :(得分:3)

使用指针语义捕获this捕获。改变这个:

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

解决了这个问题:

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

答案 1 :(得分:0)

行:makeSecretPrinter().run(),它实际上先执行makeSecretPrinter(),然后执行run()。但是,当run()正在执行时,它已经超出了makeSecretPrinter()的范围。因此,lambda函数没有得到正确的值作为要调用的参数。

请注意,您的类仅接收函数指针(或函数引用,它们在语义上是相同的。)这意味着该值不会传递到Copier类。当Copier尝试'run()'时,它需要在makeSecretPrinter()中拾取变量。但是,正如我所说,当'run()'被执行时,它超出了范围。