我正在写一本教育用的传送器。
我的transpiler从我的语言转换为C语言。
我现在正在编写闭包语法分析器和代码生成组件。
我看到有人说C++中的闭包实际上被转换为未命名的结构类型,其中包含捕获的值作为变量。
Here is the reference
.
此代码
int c = 10;
auto closure = [=] () -> void {
std::cout << c << std::endl;
};
他们说,基本上是在引擎盖下转化成这样的东西。
struct UNNAMED_TYPE_0 {
int c;
void operator() () const {
std::cout << c << std::endl;
}
};
如果有人想改变它
int c
执行闭包时,他/她必须将此变量作为ref传递
[&c] () -> void { /* mutation comes here */}
. 但问题是如果我们宣布
内景c
在函数内部创建闭包,如下所示
function<void()> aFunction() {
int c = 10;
auto closure = [&c] () -> void { c = 100; }
return closure;
}
aFunction() ();
内景c
被抓获,但一旦
aFunction
堆栈被破坏
内景c
也被摧毁了。这意味着,如果我们尝试在释放的地址上写入,我们可能会运行
segmentation fault(core dumped)
希望指针错误。
在里面
Java语言
,
public interface VoidCallback {
public void method();
}
public void aMethod() {
int c = 10;
VoidCallback callback = () -> c = 10;
}
Java处理这样的闭包,并确保闭包捕获(比如隐式捕获)不会发生变化。这意味着Java传递闭包捕获副本而不是引用。对于引用或类类型,只有对象指针作为副本传递。尽管指针引用不会发生变化,但您可以在指针指向的对象内变化内容。这与前一个基本相同。
在里面
目标-C
,
__block int c = 0;
// they say, this `int c` is allocated in heap instead of stack
// so that it exists until the closure is finished executing.
void (^ closure) (void) = ^void() {
c = 10; // this is valid
// this actually changed the `int c`'s value
};
在里面
敏捷的
var a : Int = 10;
var closure = { [] () -> Void in
a = 10; // this is valid by default
// unless `var a` is declared as `let a`
};
因此,这意味着Objective-C和Swift将原语捕获列表分配为指针。这样它们就可以变异。
P、 S:请注意,Swift闭包捕获列表仅适用于类或引用类型,但这里我指的是对基元类型的隐式捕获。
这是
__块int c=0;
void(^闭包)(void)=^ void(){
c=10;
};
与此(基本上)相同
int * c = malloc(sizeof(int));
*c = 0;
void (^ closure) (void) = ^void() {
*c = 10;
if (c) {
free(c);
c = NULL;
}
};
我认为,在闭包完成后立即释放指针变量将太糟糕了。
如果有很多闭包指向该变量,并且在执行时会发生变化,该怎么办?
如果这些闭包是在不同的线程之间传递或执行的呢?
我提出了一个使用引用计数技术的解决方案。
当创建一个改变变量的闭包时,该变量将被保留。
当变异变量的闭包被破坏时,变量将被释放。
当没有闭包时,变量将真正被释放。
为了确保线程安全,我会在闭包操作引用计数技术时锁定和解锁计数器变量地址。
如果还有其他技巧,请指导我。
任何语言的解释都将不胜感激。
目前,我对汇编语言一无所知。
对于主持人,
由于这个问题是一种研究,我恳请你不要太宽泛。