How can I track object lifetime in C++11 lambda?(如何在C++11lambda中跟踪对象的生存期?)
                            本文介绍了如何在C++11lambda中跟踪对象的生存期?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!
                        
                        问题描述
有时,我们对捕获对象状态的lambda的生存期一无所知(例如,从Object返回它,将其注册为回调而不能取消订阅等)。如何确保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;
}
这个程序只是巧合地打印"WROR"而不是"OK"(http://ideone.com/Srp7RC)(它似乎只是为第二个Foo对象重用了相同的内存)。无论如何,这是一个错误的程序。当我们执行f时,第一个Foo对象已死。
推荐答案
延长对象生存期
lambda可以捕获指向this的共享指针,因此对象不会在至少存在一个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;
};
http://ideone.com/Ucm2p8
通常,这不是一个好的解决方案,因为这里以非常隐式的方式延长了对象的生存期。这是在对象之间生成循环引用的非常简单的方法。
跟踪对象生存期
lambdas可以跟踪捕获的对象生存期,并仅在该对象仍处于活动状态时使用该对象。
class Foo : public std::enable_shared_from_this<Foo> {
public:
    Foo(const std::string& i_name) : name(i_name) {}
    std::function<void()> GetPrinter() {
        std::weak_ptr<Foo> weak_this = shared_from_this();
        return [weak_this]() {
            auto that = weak_this.lock();
            if (!that) {
                std::cout << "The object is already dead" << std::endl;
                return;
            }
            std::cout << that->name << std::endl;
        };
    }
    std::string name;
};
http://ideone.com/Wi6O11
在没有共享指针的情况下跟踪对象生存期
作为hvdnoted,我们不能总是确保对象由shared_ptr管理。在这种情况下,我建议使用以下lifetime_tracker。它是独立的,不会影响您管理对象生存期的方式。
struct lifetime_tracker
{
private:
    struct shared_state
    {
        std::uint32_t count : 31;
        std::uint32_t dead  : 1;
    };
public:
    struct monitor
    {
        monitor() : state(nullptr) {}
        monitor(shared_state *i_state) : state(i_state) {
            if (state)
                ++state->count;
        }
        monitor(const monitor& t) : state(t.state) {
            if (state)
                ++state->count;
        }
        monitor& operator=(monitor t) {
            std::swap(state, t.state);
            return *this;
        }
        ~monitor() {
            if (state) {
                --state->count;
                if (state->count == 0 && state->dead)
                    delete state;
            }
        }
        bool alive() const {
            return state && !state->dead;
        }
    private:
        shared_state *state;
    };
public:
    lifetime_tracker() : state(new shared_state()) {}
    lifetime_tracker(const lifetime_tracker&) : state(new shared_state()) {}
    lifetime_tracker& operator=(const lifetime_tracker& t) { return *this; }
    ~lifetime_tracker() {
        if (state->count == 0)
            delete state;
        else
            state->dead = 1;
    }
    monitor get_monitor() const {
        return monitor(state);
    }
private:
    shared_state *state;
};
用法示例
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;
};
                        这篇关于如何在C++11lambda中跟踪对象的生存期?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
				 沃梦达教程
				
			本文标题为:如何在C++11lambda中跟踪对象的生存期?
				
        
 
            
        
             猜你喜欢
        
	     - 如何提取 __VA_ARGS__? 2022-01-01
 - 从父 CMakeLists.txt 覆盖 CMake 中的默认选项(...)值 2021-01-01
 - 使用 __stdcall & 调用 DLLVS2013 中的 GetProcAddress() 2021-01-01
 - 将 hdc 内容复制到位图 2022-09-04
 - 哪个更快:if (bool) 或 if(int)? 2022-01-01
 - 将函数的返回值分配给引用 C++? 2022-01-01
 - OpenGL 对象的 RAII 包装器 2021-01-01
 - DoEvents 等效于 C++? 2021-01-01
 - GDB 不显示函数名 2022-01-01
 - XML Schema 到 C++ 类 2022-01-01
 
						
						
						
						
						