在 C++14 中使用通用 lambda 和自动返回类型特征获得不同的结果

Different results obtained by using generic lambdas and automatic return type feature in C++14

本文关键字:特征 返回类型 结果 C++14 lambda      更新时间:2023-10-16

我正在尝试使用C++在python中实现这一段高阶函数:

def add1(x):
    def helper():
        nonlocal x
        x += 1
        return x
    return helper

以下是我创建的三个版本:

#include <iostream>
#include <functional>
using namespace std;
function<int(void)> add1_v1(int x) {
    function<int(void)> g = [&x]() {return ++x;};
    return g;
}
auto add1_v2(int x) {
    function<int(void)> g = [&x]() {return ++x;};
    return g;
}
auto add1_v3(int x) {
    auto g = [&x]() {return ++x;};
    return g;
}
int main() {
  auto a = add1_v1(100);
  auto b = add1_v2(100);
  auto c = add1_v3(100);
  for(int i = 0; i < 3; ++i) {
      cout << a() << endl;
  }
  cout << "-------------------------------------------" << endl;
  for(int i = 0; i < 3; ++i) {
      cout << b() << endl;
  }
  cout << "-------------------------------------------" << endl;
  for(int i = 0; i < 3; ++i) {
      cout << c() << endl;
  }
  return 0; 
}

输出为:

101
102
103
-------------------------------------------
4239465
4239466
4239467
-------------------------------------------
4201325
4201325
4201325

只有add1_v1符合我想要的。谁能解释一下我的原因?

原因是这是未定义的行为。

内部 lambda 通过引用捕获x

问题是,一旦add()返回,它的参数就会被销毁,并且返回的 lambda 对已销毁对象的引用悬而未决。

lambda 必须按值捕获x;在我看来,你在这里真正想做的是一个可变的 lambda:

auto add(int x) {
    function<int(void)> g = [x]() mutable {return ++x;};
    return g;
}

请注意,此方法在随后复制返回的 lambda 时具有某些含义;但只要返回的 lambda 在其剩余的生命周期中保持"在一个位置",生成的语义就可能是您所期望的。

所有这些都是格式不正确的,因为您在 lambda 中通过引用捕获x,但x是一个局部变量,当退出函数时会被销毁 add ,然后引用变得悬空,取消引用它会导致 UB,这意味着一切皆有可能; 即使是第一种情况似乎也可以正常工作。

不是答案,如果您将参数签名更改为 add1_v*(int&&x(,似乎所有版本的函数都可以正常工作