【问题标题】:no-return lambda strange behavior无返回 lambda 奇怪的行为
【发布时间】:2019-01-24 07:30:51
【问题描述】:

我只是发现了一些无法理解的东西。我觉得应该和函数栈和一些未定义的行为有关。

假设我有一个函数工厂模板(傻一个):

template <unsigned int N=10>
std::function<int&&(const int& n)> build_add_function() {
    return [](const int& n) -> int&& {std::move(n+N);};
}

如您所见,它缺少非 void 函数的 return 语句,因此编译器会向我发出警告... 奇怪的是它“按预期工作”

int main() {
  auto foo = build_add_function();
  std::cout << foo(10);
}

主要输出:20

当然,为了修复代码,我添加了return 语句,它给了我一个分段错误

Process finished with exit code 139 (interrupted by signal 11: SIGSEGV)

我肯定对我正在做的事情有一些误解,但我就是无法理解。有人会向我解释这里发生了什么吗? 我正在使用gcc 版本8.0.1

编辑:刚刚在 gcc 4.8.1 上进行了测试,并且使用 return 语句按预期工作,没有编译错误。

它是编译器的东西吗?

【问题讨论】:

    标签: c++ gcc lambda return c++14


    【解决方案1】:

    这两种情况都是未定义的行为。

    非空函数的行为缺少return 语句是undefinedmain() 除外),这意味着一切皆有可能。即使你可能得到“正确”的结果,你也不应该依赖它。

    当您添加像return std::move(n+N); 这样的return 语句时,您正在尝试返回对临时的引用,该引用总是悬空的,并且对它的取消引用也会导致 UB。

    【讨论】:

    • 这个想法是我将变量标记为移动而不是复制,所以修复只是使用复制来代替?
    • 那么,如果它用于自定义类,这会起作用吗?或者如何解决它?
    • @Netwave 对不起,我错了。它与内置类型无关。请注意,std::move 不执行移动操作,它只是将操作数转换为右值。 (顺便说一句,std::move 实际上是多余的,n+N 已经是一个右值。)所以 lambda 所做的就是将一个临时值绑定到右值引用并返回它。临时对象立即被销毁,所以返回的引用总是悬空的。将返回类型更改为int 就可以了。
    • 实际上 move 可能是多余的,但这不是问题,问题是编译器抱怨在没有中间存储变量的操作上直接使用move
    • @Netwave 你的意思是编译器在抱怨std::move(n+N)?
    猜你喜欢
    • 2015-04-03
    • 2015-12-28
    • 2011-06-23
    • 2013-12-11
    • 2012-12-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-04
    • 1970-01-01
    相关资源
    最近更新 更多