受到 Herb Sutter 引人入胜的演讲Not your Father's C++的启发,我决定使用 Microsoft 的 Visual Studio 2010 再看看最新版本的 C++。我对 Herb 关于 C++ 是“安全”的断言特别感兴趣,因为我没有听说过 C ++11 解决了众所周知的向上 funarg 问题。据我所知,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++ 没有得到任何结果)。人们是否意识到这一点?是否有人正在研究解决方案或描述解决方法?