C ++ 11中lambda的内存管理 [英] memory management for lambda in C++11

查看:131
本文介绍了C ++ 11中lambda的内存管理的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有人可以描述为什么此代码不起作用(在从呼叫返回之前在GCC4.7.3 seg-faults上)吗?

Could someone describe why this code doesn't work (on GCC4.7.3 seg-faults before returning from call)?

#include <iostream>
#include <functional>
#include <memory>

using namespace std;

template<typename F>
auto memo(const F &x) -> std::function<decltype(x())()> {
    typedef decltype(x()) return_type;
    typedef std::function<return_type()> thunk_type;
    std::shared_ptr<thunk_type> thunk_ptr = std::make_shared<thunk_type>();

    *thunk_ptr = [thunk_ptr, &x]() {
        cerr << "First " << thunk_ptr.get() << endl;
        auto val = x();
        *thunk_ptr = [val]() { return val; };
        return (*thunk_ptr)();
    };

    return [thunk_ptr]() { return (*thunk_ptr)(); };
};

int foo() {
    cerr << "Hi" << endl;
    return 42;
}

int main() {
    auto x = memo(foo);
    cout << x() << endl ;
    cout << x() << endl ;
    cout << x() << endl ;
};

我最初的假设:

  1. 每个std::function<T()>都是对表示关闭的某个对象的引用/shared_ptr. IE.提取价值的生命周期受到它的限制.
  2. std::function<T()>对象具有赋值运算符,该赋值运算符将放弃旧的闭包(终止生命周期中选择的值),并将获得新值的所有权.
  1. each std::function<T()> is kinda reference/shared_ptr to some object that represents closure. I.e. life-time of picked up value is limited by it.
  2. std::function<T()> object have assignment operator that will abandon old closure (end life-time picked values) and will take ownership for a new value.

P.S.在阅读关于C ++ 11中的懒惰的问题

推荐答案

这是有问题的代码:

[thunk_ptr, &x]() {
    auto val = x();
    *thunk_ptr = [val]() { return val; };
    return (*thunk_ptr)(); // <--- references a non-existant local variable
}

问题在于本地thunk_ptr是上下文的副本.也就是说,在分配*thunk_ptr = ...中,thunk_ptr引用功能对象拥有的副本.但是,通过分配,功能对象将不复存在.也就是说,在下一行thunk_ptr指的是刚刚被破坏的对象.

The problem is that the local thunk_ptr is a copy from the context. That is, in the assignment *thunk_ptr = ... the thunk_ptr refers to the copy owned by the function object. However, with the assignment the function object ceases to exist. That is, on the next line thunk_ptr refers to a just destroyed object.

有几种方法可以解决此问题:

There are a few approaches to fix the problem:

  1. 不要花哨,只需返回val.这里的问题是return_type可能是引用类型,将导致此方法失败.
  2. 直接从赋值返回结果:在赋值thunk_ptr仍然有效之前,赋值后仍返回对std::function<...>()对象的引用:

  1. Instead of getting fancy, just return val. The problem here is that return_type may be a reference type which would cause this approach to fail.
  2. Return the result straight from the assignment: prior to the assignment thunk_ptr is still alive and after the assignment it still return a reference to the std::function<...>() object:

return (*thunk_ptr = [val](){ return val; })();

  • 保护thunk_ptr的副本,并使用该副本在return语句中调用函数对象:

  • Safe a copy of thunk_ptr and use this copy to call the function object in the return statement:

    std::shared_ptr<thunk_type> tmp = thunk_ptr;
    *tmp = [val]() { return val; };
    return (*tmp)();
    

  • 保存对std::function的引用的副本,并使用它代替引用属于覆盖的闭包的字段:

  • Save a copy of reference to std::function and use it instead of referring to field that belongs to overwritten closure:

    auto &thunk = *thunk_ptr;
    thunk = [val]() { return val; };
    return thunk();
    

  • 这篇关于C ++ 11中lambda的内存管理的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆