【问题标题】:weak_ptr, shared_ptr in lambda capture list and std::queue<T,Container>::emplacelambda 捕获列表和 std::queue<T,Container>::emplace 中的 weak_ptr、shared_ptr
【发布时间】:2020-02-18 12:36:33
【问题描述】:

我有一个函数,它使用 std::queue's 内置 emplace 将 lambda 排入队列。我创建了shared_ptr 对象(任务),稍后我将在 lambda 中捕获它。

    template<typename Func, typename... Args>
    auto submit(Func&& f, Args&&... args)
    {
        using result_type = std::result_of_t<Func(Args...)>;
        using pckg_task_type = std::packaged_task<result_type()>;

        auto task = std::make_shared< pckg_task_type >(
                    std::bind(std::forward<Func>(f), std::forward<Args>(args)...) );
        ...
    }

这是造成混乱的部分:

案例 1:完美运行

            tasks.emplace(
                [task](){
                    auto wptr = std::weak_ptr<pckg_task_type>(task);
                    if( auto p = wptr.lock() )
                    {
                        (*p)();
                    }
                    else
                        throw std::runtime_error("weak error");
                }
            );

案例2:立即抛出异常

                tasks.emplace(
                [wc = std::weak_ptr<pckg_task_type>(task)](){
                    if( auto p = wc.lock() )
                    {
                        (*p)();
                    }
                    else
                        throw std::runtime_error("weak error");
                }
            );

任务定义为

std::queue< std::function<void()> > tasks;

从案例 2 调用 lambda 而不将其放入队列不会引发异常。

谁能解释上述案例之间的区别?问题出在哪里?

【问题讨论】:

    标签: c++ lambda capture weak-ptr emplace


    【解决方案1】:

    问题在于,在情况 2 中,task 共享指针没有保存在任何地方,而保存在 lambda 捕获中的弱指针 wc 在您从 submit 返回后立即过期。调用 lambda 时,wc.lock() 返回一个空指针。

    您可能需要将 task shared_ptr 保存在某处,以用于入队函数对象的生命周期。或者您根本不需要 weak_ptr,只需将 task shared_ptr 保存在 lambda 捕获中并直接在 lambda 主体中使用即可。

    【讨论】:

    • 有道理。谢谢很多:)
    【解决方案2】:

    您的第一个案例将共享指针复制到 lambda 中,因此将在 lambda 的生命周期内使其保持活动状态,lambda 内部的弱指针是没有意义的,因为您创建了一个弱指针然后立即锁定它,这将永远不会失败。

    第二种情况只是捕获一个弱指针,共享指针在提交结束时超出范围,大概没有其他对它的引用,所以指针被删除。这仅在您的 lambda 开始执行并在提交结束之前锁定指针时才有效。

    【讨论】:

      猜你喜欢
      • 2016-07-31
      • 2017-12-10
      • 2018-05-23
      • 1970-01-01
      • 2019-10-20
      • 2013-10-31
      • 2015-07-23
      • 1970-01-01
      • 2011-06-26
      相关资源
      最近更新 更多