C++ 如何在C++;11兰巴?

C++ 如何在C++;11兰巴?,c++,c++11,lambda,shared-ptr,weak-ptr,C++,C++11,Lambda,Shared Ptr,Weak Ptr,有时,我们对捕获对象状态的lambda的生存期一无所知(例如,从对象返回它,将它注册为回调,但不能取消订阅等)。如何确保lambda在调用时不会访问已经销毁的对象 #include <iostream> #include <memory> #include <string> class Foo { public: Foo(const std::string& i_name) : name(i_name) {} std::functi

有时,我们对捕获对象状态的lambda的生存期一无所知(例如,从对象返回它,将它注册为回调,但不能取消订阅等)。如何确保lambda在调用时不会访问已经销毁的对象

#include <iostream>
#include <memory>
#include <string>

class Foo {
public:
    Foo(const std::string& i_name) : name(i_name) {}

    std::function<void()> GetPrinter() {
        return [this]() {
            std::cout << name << std::endl;
        };
    }

    std::string name;
};

int main() {
    std::function<void()> f;

    {
        auto foo = std::make_shared<Foo>("OK");
        f = foo->GetPrinter();
    }

    auto foo = std::make_shared<Foo>("WRONG");

    f();

    return 0;
}
#包括
#包括
#包括
福班{
公众:
Foo(const std::string&i_name):name(i_name){}
std::函数GetPrinter(){
返回[此](){
std::无法延长对象生存期
lambda可以捕获指向此
的共享指针,因此当至少存在一个lambda时,对象不会死亡

class Foo : public std::enable_shared_from_this<Foo> {
public:
    Foo(const std::string& i_name) : name(i_name) {}

    std::function<void()> GetPrinter() {
        std::shared_ptr<Foo> that = shared_from_this();

        return [that]() {
            std::cout << that->name << std::endl;
        };
    }

    std::string name;
};
用法示例

class Foo {
public:
    Foo(const std::string& i_name) : name(i_name) {}

    std::function<void()> GetPrinter() {
        auto monitor = tracker.get_monitor();

        return [this, monitor]() {
            if (!monitor.alive()) {
                std::cout << "The object is already dead" << std::endl;
                return;
            }

            std::cout << this->name << std::endl;
        };
    }

private:
    lifetime_tracker tracker;

    std::string name;
};
class-Foo{
公众:
Foo(const std::string&i_name):name(i_name){}
std::函数GetPrinter(){
自动监视器=跟踪器。获取监视器();
返回[此,监视器](){
如果(!monitor.alive()){

std::coutStas的答案是好的,当您可以确定对象由
共享的\u ptr
管理时,但这并不总是可能的。不过,您始终可以做的是跟踪对象的生存期,并在lambda中添加断言

void ignore(void *) { }

class Foo {
public:
    Foo(const std::string& i_name) : name(i_name) {}
    Foo(const Foo& other) : name(other.name) {}
    Foo(Foo&& other) : name(std::move(other.name)) {}
    Foo& operator=(Foo other) { swap(*this, other); return *this; }
    friend void swap(Foo& a, Foo& b) { using std::swap; swap(a.name, b.name); }

    std::function<void()> GetPrinter() {
        std::weak_ptr<void> monitor = this->monitor;

        return [=]() {
            assert (!monitor.expired());
            std::cout << name << std::endl;
        };
    }

    std::string name;

private:
    std::shared_ptr<void> monitor{this, ignore};
};
void忽略(void*){}
福班{
公众:
Foo(const std::string&i_name):name(i_name){}
Foo(constfoo&other):name(other.name){}
Foo(Foo&&other):名称(std::move(other.name)){}
Foo&operator=(Foo-other){swap(*this,other);返回*this;}
朋友无效交换(Foo&a,Foo&b){使用std::swap;交换(a.name,b.name);}
std::函数GetPrinter(){
std::weak_ptr monitor=此->监视器;
返回[=](){
断言(!monitor.expired());

std::难道@P0W-hmm不接受该代码,可能clang已经过时了吗?我想clang-3.3应该编译这个(现在不能检查)。是的,在最新的一个上是这样的,谢谢!是的,好主意。但是您需要定义复制构造函数。现在,如果您复制Foo对象,它将表现不正确。@Stas Right,谢谢您指出这一点。还有一个移动构造函数和赋值运算符。
class Foo {
public:
    Foo(const std::string& i_name) : name(i_name) {}

    std::function<void()> GetPrinter() {
        auto monitor = tracker.get_monitor();

        return [this, monitor]() {
            if (!monitor.alive()) {
                std::cout << "The object is already dead" << std::endl;
                return;
            }

            std::cout << this->name << std::endl;
        };
    }

private:
    lifetime_tracker tracker;

    std::string name;
};
void ignore(void *) { }

class Foo {
public:
    Foo(const std::string& i_name) : name(i_name) {}
    Foo(const Foo& other) : name(other.name) {}
    Foo(Foo&& other) : name(std::move(other.name)) {}
    Foo& operator=(Foo other) { swap(*this, other); return *this; }
    friend void swap(Foo& a, Foo& b) { using std::swap; swap(a.name, b.name); }

    std::function<void()> GetPrinter() {
        std::weak_ptr<void> monitor = this->monitor;

        return [=]() {
            assert (!monitor.expired());
            std::cout << name << std::endl;
        };
    }

    std::string name;

private:
    std::shared_ptr<void> monitor{this, ignore};
};