「C++11」Lambda 表达式

 a lambda维基百科上面对于 lambda 的引入是以下描述的:html

在标准 C++,特别是当使用 C++ 标准程序库算法函数诸如 sort 和 find。用户常常但愿可以在算法函数调用的附近定义一个临时的述部函数(又称谓词函数,predicate function)。因为语言自己容许在函数内部定义类型,能够考虑使用函数对象,然而这一般既麻烦又冗赘,也阻碍了代码的流程。此外,标准 C++ 不容许定义于函数内部的类型被用于模板,因此前述的做法是不可行的。C++11 对lambda的支持能够解决上述问题。ios

lambda 表达式的简单语法以下:[capture] (parameters) -> return value { body }c++

一、最简单的例子:算法

#include <iostream> using namespace std; int main() { auto func = [] () { cout << "Hello world"; }; func(); }

上面的 lambda 表达式 func 没有传入任何参数,也没有返回值,甚至咱们能够对其简写成:auto func = [] { cout << "Hello world"; } 。而且配合 C++11标准加入的 auto 自动类型判断,省去了之前定义函数指针冗杂繁琐的过程,程序看上去如何优雅、简洁。shell

二、更加深刻的示范:编程

假设咱们有一个存放书籍地址的类,须要传入一个“搜索知足条件地址”的函数,而且将类定义成以下模样:闭包

class AddressBook
{
public:
    template<typename Func>
    std::vector<std::string> findMatchingAddresses (Func func)
    { 
        std::vector<std::string> results;
        for ( auto itr = _addresses.begin(), end = _addresses.end(); itr != end; ++itr )
        {    
            if ( func( *itr ) )
            {
                results.push_back( *itr );
            }
        }
        return results;
    }
private:
    std::vector<std::string> _addresses;
};

类 AddressBook 封装了 findMatchingAddresses 函数,返回知足咱们须要的书目,下面咱们看看 lambda 表达式如何实现这一过程:函数

AddressBook global_address_book;
vector<string> findAddressesFromOrgs ()
{
    return global_address_book.findMatchingAddresses( 
        [] (const string& addr) { return addr.find( ".org" ) != string::npos; } 
    );
}

上面函数返回知足地址中带有 ".org" 字样的书籍条目,lambda 表达式虽然没有定义返回类型,可是编译器能够根据咱们的 return 语句自动判断返回值是 boolean 类型。咱们的 lambda 表达式中 [] 并无 capture 任何变量,再下面的例子中将展现 [&] :oop

string name;
cin >> name;
return global_address_book.findMatchingAddresses( 
    [&] (const string& addr) { return addr.find( name ) != string::npos; } 
);

再次注意到,类 global_address_book 居然可以访问到咱们定义的局部变量 name 字符串,这正是 lambda 表达式的强大之处,[&] 表明 lambda body 中用到的变量都以“reference”的方式使用,还有更多的 capture 用法这里就再也不叙述,有兴趣进一步了解的同窗能够自行搜索。性能

三、Lambda 表达式使 STL 更增强大:

传统的状况下,咱们会用下面的方式去访问容器里面的数据:

vector<int> v;
v.push_back( 1 );
v.push_back( 2 );
//...
for ( auto itr = v.begin(), end = v.end(); itr != end; itr++ )
{
    cout << *itr;
}

可是当咱们有了 Lambda 以后,利用 STL 里面的 for_each ,将会变成下面的代码:

vector<int> v;
v.push_back( 1 );
v.push_back( 2 );
//...
for_each( v.begin(), v.end(), [] (int val)
{
    cout << val;
});

你可能会想,上面的 for_each 循环,会不会使咱们的程序有性能上的损耗?答案是否认的:for_each 的效率和迭代的效率是一致的,甚至加上 Lambda 以后,for_each 会利用 "loop unrolling" 机制使程序运行的更快。

Lambda 的引入给咱们带来了一种全新的编程体验,它可让咱们把 "function" 当作是 "data" 同样传递,而且使咱们从繁琐的语法中解放出来,更加关注于 "算法" 自己。咱们也称 Lambda 为 Closure(闭包),顾名思义,这使咱们的函数变得更加私有,因此限制了别人的访问,同时咱们也能够更加方便的编程。

四、Lambda 与 资源管理:

前面在个人 「理解智能指针」一文中提到,智能指针能够利用 C++ 的 RAII(Resource acquisition is initialization) 特性,在类型(class)的析构函数时来完成自动释放指针所指向对象的目的。一样,在 Lambda 中,又把 RAII 这一特性体现的淋漓尽致:

class ScopeGuard
{
public:
    explicit ScopeGuard(std::function<void()> onExitScope)
        : onExitScope_(onExitScope)
    { }
    ~ScopeGuard()
    {
            onExitScope_();
    }
private:
    std::function<void()> onExitScope_;
private: // noncopyable
    ScopeGuard(ScopeGuard const&);
    ScopeGuard& operator=(ScopeGuard const&);
};
int main() {
 HANDLE h = CreateFile(...); ScopeGuard onExit([&] { CloseHandle(h); });
    ...
return 0;
}

看到上面的代码,我已经被 C++11 引入 Lambda 以后所带来的强大功能所折服了。咱们没必要担忧什么时候去释放资源,而且连释放资源的方式「如 CloseHandle(h)」也与咱们的代码紧密的融合在了一块儿,这将是十分美妙的一件事情。

五、Lambda 究竟是什么类型:

auto func = [] () { cout << "hello world"; };
std::function<void ()> func = [] () { cout << "hello world"; };

auto func = [] (int val) { cout << val; return false; };
std::function<bool (int)> func = [] (int val) { cout << val; return false; };

 上面的上下 2 行代码效果是等效的,看到这里是否有种似曾相识的感受?那 Lambda 和 咱们定义的函数指针有什么区别呢:

typedef int (*func)();
func f = [] () -> int { return 2; };
f();

没错,这段代码是能够正常运行的,由于 Lambda 表达式中并无 capture 任何本地变量,所以会被编译成普通的函数指针。最后采用 coolshell 里面 Lambda 的 2 点总结: 1)能够定义匿名函数,2)编译器会把其转成函数对象。 

六、 使用 Lambda 进行代码委托(调用):

 

「参考资料」

http://zh.wikipedia.org/wiki/C%2B%2B11

http://mindhacks.cn/2012/08/27/modern-cpp-practices/

http://www.cprogramming.com/c++11/c++11-lambda-closures.html

http://coolshell.cn/articles/5265.html

相关文章
相关标签/搜索