C++ Lambda的内存布局

3
在尝试更好地理解C++ lambda的实现时,我让编译器将lambda视为一个对象,并且似乎它们在内存中的布局方式相同。
注意:这只是为了澄清问题,我不建议在生产环境中写这种类型的黑客代码。
这是语言规范保证的还是编译器实现的细节?
struct F
{
    int a;  int b;  int c;
    void printLambdaMembers()
    {
        cout << this << endl; // presumably the lambda 'this'
        cout << a << endl; // prints 5   
        cout << b << endl;
        cout << c << endl;
    }
};

void demo()
{
    int a = 5;
    int b = 6;
    int c = 7;
    auto lambda = [a,b,c]() { cout << "In lambda!\n";  };
    // hard cast the object member function pointer to the lambda function 
    void(decltype(lambda)::*pf)() const = (void(decltype(lambda)::*)() const) (&F::printLambdaMembers);
    // run the member function on the lambda pointer
    (lambda.*pf)();  // we get 5,6,7

}

6
“我愚弄了编译器,让它把一个Lambda当作对象处理。” 这很有趣,因为按照定义,Lambda本来就是匿名类型的对象 :) - YSC
2
检查标准难道真的那么困难吗?我们需要为每一个可能的细节都重新表述问题吗? - underscore_d
1
@YSC 更严谨的说法可能是“我通过违反严格别名规则,欺骗编译器将 lambda 当作某个不相关类类型的对象”,并伴随着 UB 的相关症状。你也可以(可能)用 int[3] 对象做类似的事情。 - Caleth
2
@Caleth 不太有趣。 - YSC
@YSC 太好了,现在我无法编辑我的问题,因为这将使所有这些评论无效。 - Gonen I
4
是的,您可以这样做。问题/答案的改进优先于评论的相关性。编辑您的问题,并将评论标记为过时。 - YSC
3个回答

7
标准并不要求Lambda闭包有特定的布局,详见[expr.prim.lambda.closure]

Lambda表达式的类型(也是闭包对象的类型)是一个独特的、未命名的非联合类类型,称为闭包类型,其属性如下所述。

...

闭包类型不是聚合类型。 实现可能会从下面描述的方式不同地定义闭包类型,前提是这不改变程序的可观察行为,除了更改以下内容:

  • 闭包类型的大小和/或对齐方式
  • 闭包类型是否可以被平凡地复制
  • 闭包类型是否是标准布局类

在闭包类型中,实现不应添加右值引用类型的成员。


然而,为了符合平台ABI并使目标文件可以互操作,编译器可能必须以完全相同的方式布局和名称化Lambda对象。

4
这完全是由实现定义的。
然而,由于 lambda 只是类的实例,因此生成它们的编译器会使它们看起来像任何其他类一样。

2

具体实现。

此外,在你的情况下,Lambda表达式的捕获未被使用,因此甚至可能被省略...


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接