lambda的内存管理在C ++ 11 [英] memory managment for lambda in C++11
问题描述
有人能描述为什么这个代码不工作(在从调用返回之前的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 ;
};
我的原始假设:
- 每个
std :: function< T()>
是表示闭包的某个对象的kinda reference / shared_ptr。也就是说 -
std :: function< T()>
对象具有赋值运算符
- 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. 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.
PS在我阅读有关C ++ 11中延迟的问题后提出的这个问题
P.S. This question raised after I read question about lazy in 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:
- 只需返回
val
即可。这里的问题是return_type
可能是一种引用类型,会导致此方法失败。 -
返回结果从赋值:在赋值之前
thunk_ptr
仍然是活的,在赋值后它仍然返回对std :: function <...的引用>()
object:
- Instead of getting fancy, just return
val
. The problem here is thatreturn_type
may be a reference type which would cause this approach to fail. 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 thestd::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();
这篇关于lambda的内存管理在C ++ 11的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!