最近在看各种源代码。发现很多c++代码使用到了c++ 11的新标准,其中lambda匿名函数使用的十分多。于是我只能去补充下我原来的 c++知识。
通常来说,lambda表达式是一种可以构建匿名函数的表达式。当然,我对这种不是特别精通,只从我对一些语言的认识说一下我随便试试c++新特性时的感受。
对于一种编程语言来说,将函数当做对象而言我认为是很直观的事。然后在过去的c/c++语言中,这种实现通常需要使用非常恼人的指针。举例来说, 申明了一个返回值为整数,取两个整数为参数的函数。而在c++11中,这种可以非常简洁的表示为 这种类似的表示。不过最重要的是,可以实现匿名函数,以及动态的生成函数。 下面我做下简要的说明。
c++11的标准可以以如下的方式申明匿名函数,比如说 auto f = [] () -> int { return 83;} ;其中[]中的依赖变量,很好理解。
那么问题是(我特别改变了说法),当出现如下情况时,
class Test {
public:
int x;
Test(int n) : x(n) {};
std::function <int ()> get_fun() {
return [this]() { return this->x;};
}
~Test() { cout<<"delete\n";}
};
当我们使用如下调用时,
Test *a = new Test(12);
auto f = a->get_fun();
cout<<f()<<endl;
delete a;
cout<<f()<<endl;
貌似很合理。然而,这样会造成内存泄露。
当我们把代码改成如下时,
Test *a = new Test(12);
auto f = a->get_fun();
cout<<f()<<endl;
delete a;
for(int i = -14;i < 12;++i) {
Test *temp = new Test(i);
}
cout<<f()<<endl;
出现的结果为:
也就是说,对于前一个元素的返回的函数的调用是可能会对不属于其访问空间的内存进行读取和修改。这是很糟糕的。
那么结论来了。当然我只是很浅显的谈一下我的感受。我认为c++并没有实现真正的函数闭包。据说c++的匿名函数是使用类来实现的。如果是采用直接将依赖值([]中的值或者引用)作为类变量这种naive实现的话,是符合目前的结果的。我并不是很懂在这里不做展开。
另一个很明显的c++函数没有闭包的例子是
std::function <int ()>get(int n) {
int x = n;
cout<<x<<endl;
auto f = [&x]() -> int { x = x + 1;return x;};
cout<<x<<endl;
return f;
}
std::function <int (int) > closure(){
int sum = 0;
return [&sum] (int x) { sum += x;return sum;};
}
int main() {
auto f_ = get(12);
cout<<f_()<<endl;
auto f1 = closure();
for(int i = 0;i < 10;++i) {
cout<<f1(i)<<endl;
}
}
在这种情况下,出现的结果是
显然,我认为这是不符合程序语义的。事实上,将get函数调用去掉会出现随机数。