You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

结合io_context使用enable_shared_from_this的循环引用疑问及解决

ioContext与shared_ptr循环引用的疑问及解决方案

你的理解是否正确?

完全正确,这里确实存在循环引用链:Test 对象持有 shared_ptr<io_context>(成员ioContext_),io_context 的任务队列中保存着捕获了 Test 对象强引用(shared_from_this())的lambda,而lambda又持有 Test 的强引用,最终形成 Test → io_context → lambda → Test 的循环。

当main中的myTest释放后,Test的引用计数因lambda的捕获仍不为0,io_context的引用计数因Test的持有也不为0,两者都无法被正确销毁,会造成内存泄漏。

避免循环引用的方法

1. 用weak_ptr捕获Test对象,打破强引用循环

在lambda中捕获Test的weak_ptr而非shared_ptr,需要操作对象时再升级为强引用,这样不会增加Test的引用计数,直接切断循环链:

修改start()方法的代码如下:

void start() {
    std::cout << getTime() << "at start\n";
    timer_.expires_after(std::chrono::seconds(3));
    std::weak_ptr<Test> weak_self = shared_from_this();
    timer_.async_wait([this, weak_self, io_ctx=ioContext_](const boost::system::error_code& ec)
    {
        std::cout << getTime() << "Inside wait!\n";
        if (!ec) 
        {
            io_ctx->post([weak_self]()
            {
                if (auto self = weak_self.lock()) {
                    self->printInPost();
                }
            });
        }
    });
}

这里通过weak_self捕获弱引用,在post的lambda中先调用lock()获取强引用:如果Test对象已被销毁,lock()会返回空指针,此时不会执行后续操作,既避免了循环引用,也保证了操作的安全性。

2. 将Test持有的io_context改为weak_ptr

如果Test不需要延长io_context的生命周期,可以把成员变量ioContext_从shared_ptr改为weak_ptr,这样Test不会增加io_context的引用计数,直接打破循环:

修改Test类的相关代码:

class Test : public std::enable_shared_from_this<Test> {
public:
    Test(const std::shared_ptr<boost::asio::io_context>& ioContext)
        : ioContext_(ioContext), timer_(*ioContext) {}

    void start() {
        std::cout << getTime() << "at start\n";
        timer_.expires_after(std::chrono::seconds(3));
        timer_.async_wait([this, self=shared_from_this()](const boost::system::error_code& ec)
        {
            std::cout << getTime() << "Inside wait!\n";
            if (!ec) 
            {
                if (auto io_ctx = ioContext_.lock()) {
                    io_ctx->post([self]()
                    {
                        self->printInPost();
                    });
                }
            }
        });
    }

    // 其他方法保持不变

private:
    std::weak_ptr<boost::asio::io_context> ioContext_; // 改为weak_ptr
    boost::asio::steady_timer timer_;
};

这种方式下,Test不再持有io_context的强引用,当main中的ioContext被销毁后,lock()会失败,不会执行post操作,从根源上避免了循环引用。

3. 确保lambda执行后及时释放强引用(不推荐)

如果业务逻辑能严格保证lambda执行时Test对象一定存在,可以在lambda中不捕获shared_from_this(),直接使用this指针。但这种方式风险极高,一旦Test对象提前销毁,会导致未定义行为,仅在极端场景下考虑使用。

内容的提问来源于stack exchange,提问作者proton

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 10:52:33