gpt4 book ai didi

c++ - C++11 中 lambda 的非确定性损坏

转载 作者:塔克拉玛干 更新时间:2023-11-03 00:31:12 25 4
gpt4 key购买 nike

灵感来自 Herb Sutter 引人入胜的演讲 Not your father's C++ ,我决定使用 Microsoft 的 Visual Studio 2010 再看一看最新版本的 C++。我对 Herb 断言 C++ 是“安全的”特别感兴趣,因为我没有听说 C++11 是如何解决众所周知的向上函数参数的问题。据我所知,C++11 没有解决这个问题,因此并不“安全”。

您不想返回对局部变量的引用,因为局部变量分配在堆栈帧上,该堆栈帧在函数返回后将不再存在,因此,该函数将返回一个指向已分配内存的悬垂指针将导致不确定的数据损坏。 C 和 C++ 编译器知道这一点,并会在您尝试返回指向本地的引用或指针时警告您。例如这个程序:

int &bar() {
int n=0;
return n;
}

导致 Visual Studio 2010 发出警告:

warning C4172: returning address of local variable or temporary

但是,C++11 中的 lambda 可以很容易地通过引用捕获局部变量并返回该引用,从而产生等效的悬垂指针。考虑以下函数 foo,它返回一个捕获局部变量 n 并返回它的 lambda 函数:

#include <functional>

std::function<int()> foo(int n) {
return [&](){return n;};
}

这个看似无害的函数是内存不安全的,并且是损坏数据的来源。调用这个函数在一个地方获取 lambda,然后调用 lambda 并在另一个地方打印它的返回值,为我提供了这个输出:

1825836376

此外,Visual Studio 2010 没有给出任何警告。

在我看来,这看起来像是语言中一个非常严重的设计缺陷。即使是最简单的重构也可能会产生一个 lambda 交叉堆栈框架,无声地引入非确定性数据损坏。然而,关于这个问题的信息似乎很少(例如,在 StackOverflow 上搜索“upwards funarg”和 C++ 没有找到结果)。人们是否意识到这一点?是否有人致力于解决方案或描述解决方法?

最佳答案

这不是 lambda 特有的,当涉及到生命周期时,您可以做很多坏事(并且您已经注意到至少一种情况)。虽然与 C++03 相比,C++11 在几个方面可能更安全,但 C++ 并未强调内存安全。

这并不是说 C++ 不想安全,但我要说的是通常的哲学“不要为你不用的东西买单”通常会妨碍添加安全防护措施(不考虑可能阻止对所有无效程序发出诊断的停止问题)。如果您可以解决向上函数参数问题同时不影响其他所有情况的性能,那么标准委员会就会感兴趣。 (我的意思不是刻薄,我认为这是一个有趣且困难的问题。)

既然你似乎在做一些追赶,那么到目前为止作者(和其他人)的智慧通常是避免对 lambda 表达式使用按引用捕获所有捕获(例如 [&, foo, bar]), 并且通常要小心通过引用捕获。您可以将 lambda 表达式的捕获列表视为 C++ 中您必须小心生命周期的另一个地方;或另一种观点是将 lambda 表达式视为仿函数的对象文字表示法(实际上它们是这样指定的)。当你设计一个已经考虑生命周期的类类型时,你必须小心:

struct foo {
explicit foo(T& t)
: ref(t)
{}

T& ref;
};

foo make_foo()
{
T t;
// Bad
return foo { t };
// Not altogether different from
// return [&t] {};
}

在这方面,lambda 表达式不会改变编写“明显”错误代码的现状,并且它们继承了所有先前存在的警告。

关于c++ - C++11 中 lambda 的非确定性损坏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10121291/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com