受Herb Sutter的精彩演讲Not your father's C ++的启发,我决定使用Microsoft的Visual Studio 2010再次查看最新版本的C ++。我特别感兴趣的是Herb的断言,“C ++是安全的”,因为我没有听说C ++ 11如何解决已知的向上funarg问题。据我所知,C ++ 11对解决此问题毫无作为,因此不“安全”。
您不想返回对局部变量的引用,因为该局部变量分配在堆栈帧上,在函数返回后将不存在,因此函数将返回指向已分配内存的悬空指针,这可能会导致非确定性数据损坏。 C和C ++编译器知道这一点,并且如果您尝试返回对局部变量的引用或指针,则会发出警告。例如,此程序:
然而,在C++11中,lambda表达式可以轻松地通过引用捕获本地变量并返回该引用,导致等效的悬空指针。考虑以下函数
这个看起来无害的函数存在内存不安全问题,会导致数据损坏。在一个地方调用该函数以获取lambda,然后在另一个地方调用lambda并打印其返回值,会得到以下输出结果:
此外,Visual Studio 2010没有任何警告。
对我来说,这看起来像是语言中非常严重的设计缺陷。即使是最简单的重构也可能使lambda跨越堆栈帧,悄悄地引入不确定性数据损坏。然而,关于这个问题似乎很少有信息(例如,在StackOverflow上搜索“upwards funarg”和C++没有任何命中)。人们是否知道这一点?有人正在解决方案或描述解决方法吗?
您不想返回对局部变量的引用,因为该局部变量分配在堆栈帧上,在函数返回后将不存在,因此函数将返回指向已分配内存的悬空指针,这可能会导致非确定性数据损坏。 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++没有任何命中)。人们是否知道这一点?有人正在解决方案或描述解决方法吗?